C语言 将标准输出重定向到文件

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/29154056/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 11:48:05  来源:igfitidea点击:

Redirect stdout to a file

credirectpipeposix

提问by qwerty

I am trying to do the equivalent of the bash command ls>foo.txtin C.

我正在尝试ls>foo.txt在 C中执行与 bash 命令等效的操作。

The code bellow redirects the output to a variable.

下面的代码将输出重定向到一个变量。

#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;
}

The comments lines refer to those operations that I believe that are required for the redirection. What should I change to redirect the output of ls to foo.txt?

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

回答by Razib

While dealing with redirecting output to a file you may use freopen().

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

Assuming you are trying to redirect your stdoutto a file 'output.txt' then you can write-

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

freopen("output.txt", "a+", stdout); 

Here "a+" for append mode. If the file exists then the file open in append mode. Otherwise a new file is created.

这里“ a+”表示追加模式。如果文件存在,则文件以追加模式打开。否则会创建一个新文件。

After reopening the stdoutwith freopen()all output statement (printf, putchar) are redirected to the 'output.txt'. So after that any printf()statement will redirect it's output to the 'output.txt'file.

重新打开后stdoutfreopen()所有输出语句(printf、putchar)都被重定向到'output.txt'。所以在那之后,任何printf()语句都会将它的输出重定向到“output.txt”文件。

If you want to resume printf()'s default behavior again (that is printing in terminal/command prompt) then you have to reassign stdoutagain using the following code-

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

freopen("/dev/tty", "w", stdout); /*for gcc, ubuntu*/  

Or -

或者 -

freopen("CON", "w", stdout); /*Mingw C++; Windows*/ 

However similar technique works for 'stdin'.

然而,类似的技术适用于“ stdin”。

回答by juhist

What your code essentially does is that you open a pipe, then fork the process and in the child process (in commented code) close stdout, duplicate the pipe to stdout and execute and ls command, and then (in non-commented code) write 4 bytes to the pipe. In the parent process, you read data from the pipe and wait for the completion of the child process.

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

Now you want to redirect stdout to a file. You can do that by opening a file using the open() system call and then duplicating that file descriptor to stdout. Something like (I haven't tested this so beware of bugs in the code):

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

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;

However, you can also use the freopen as suggested by the other answer.

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

However, I have several concerns of your code and of my modified code:

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

  • The pipe() and open() system calls can fail. You should always check for system call failure.

  • The fork() system call can fail. Ditto.

  • dup2() can be used instead of dup(); otherwise the code will fail if stdin is not open as it duplicates to the first available file descriptor.

  • The execlp() system call can fail. Ditto.

  • I think wait() can be interrupted by a signal (EINTR). It's recommended to wrap it around a wrapper that retries the system call if it's aborted by a signal (errno == EINTR).

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

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

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

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

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