将stdout重定向到文件

qwe*_*rty 6 c redirect posix pipe

我试图ls>foo.txt在C中做相当于bash的命令.

下面的代码将输出重定向到变量.

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>

int main(){
  int pfds[2];
  char buf[30];

  pipe(pfds);

  if (!fork()) {
    close(pfds[0]);
     //close(1);//Close stdout
    //dup(pfds[1]);
    //execlp("ls", "ls", NULL);
    write(pfds[1], "test", 5); //Writing in the pipe
    exit(0);
  } else {
    close(pfds[1]);  
    read(pfds[0], buf, 5); //Read from pipe
    wait(NULL);
  }
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

注释行指的是我认为重定向所需的那些操作.我应该更改什么来将ls的输出重定向到foo.txt?

Raz*_*zib 12

在处理将输出重定向到文件时,您可以使用freopen().

假设您正在尝试将您stdout的文件重定向到' output.txt ',那么您可以写 -

freopen("output.txt", "a+", stdout); 
Run Code Online (Sandbox Code Playgroud)

这里" a+"为追加模式.如果文件存在,则文件以追加模式打开.否则,将创建一个新文件.

重新打开后stdout,freopen()所有输出语句(printf,putchar)将重定向到'output.txt'.所以在此之后,任何printf()语句都会将其输出重定向到'output.txt'文件.

如果要再次恢复printf()默认行为(即在终端/命令提示符下打印),则必须stdout使用以下代码再次重新分配 -

freopen("/dev/tty", "w", stdout); /*for gcc, ubuntu*/  
Run Code Online (Sandbox Code Playgroud)

要么 -

freopen("CON", "w", stdout); /*Mingw C++; Windows*/ 
Run Code Online (Sandbox Code Playgroud)

但是类似的技术适用于' stdin'.

  • 我正在 Linux 和 FreeBSD 上使用 `fork()` 生成的进程进行测试,并且创建了 `output.txt` 文件,但没有收到任何文本。这在这些情况下应该有效吗?或者衍生进程上可能没有“stdout”流?也许需要某种重定向? (2认同)
  • 在此类操作之前我们需要“fclose(stdout)”吗?在这样的操作之后我们需要“fclose(stdout)”吗? (2认同)

juh*_*ist 9

你的代码基本上做的是你打开一个管道,然后分叉进程和子进程(在注释代码中)关闭stdout,将管道复制到stdout并执行和ls命令,然后(在非注释代码中)写4个字节到管道.在父进程中,您从管道中读取数据并等待子进程的完成.

现在您要将stdout重定向到文件.您可以通过使用open()系统调用打开文件,然后将该文件描述符复制到stdout来实现.类似的东西(我没有测试过,所以要注意代码中的错误):

int filefd = open("foo.txt", O_WRONLY|O_CREAT, 0666);
if (!fork()) {
  close(1);//Close stdout
  dup(filefd);
  execlp("ls", "ls", NULL);
} else {
  close(filefd);
  wait(NULL);
}
return 0;
Run Code Online (Sandbox Code Playgroud)

但是,您也可以按照其他答案的建议使用freopen.

但是,我对您的代码和修改过的代码有几个问题:

  • pipe()和open()系统调用可能会失败.您应该始终检查系统调用失败.

  • fork()系统调用可能会失败.同上.

  • dup2()可以代替dup(); 否则,如果stdin未打开,则代码将失败,因为它复制到第一个可用的文件描述符.

  • execlp()系统调用可能会失败.同上.

  • 我认为wait()可以被信号(EINTR)中断.如果它被信号(errno == EINTR)中止,建议将它包装在重试系统调用的包装器周围.