C语言 C:如何将标准错误从系统命令重定向到标准输出或文件?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3019630/
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 05:38:48  来源:igfitidea点击:

C: how to redirect stderr from System-command to stdout or file?

cstdoutstderrfile-descriptor

提问by otto

The shell command $ avrdude -c usbtinyoutputs text to stderr. I cannot read it with commmands such as head-less-more cos it is not stdout. I want the text to stdout or to a file. How can I do it in C? I have tried to solve the problem by my last questionbut still unsolved.

shell 命令将$ avrdude -c usbtiny文本输出到 stderr。我无法使用诸如 head-less-more 之类的命令读取它,因为它不是标准输出。我想要文本到标准输出或文件。我怎样才能在 C 中做到这一点?我试图通过我的最后一个问题来解决问题,但仍未解决。

回答by Dusty

I've not tried something like this in OpenBSD, but in at least a few *nix-like systems, you can do this using dup2.

我还没有在 OpenBSD 中尝试过这样的事情,但至少在一些 *nix-like 系统中,你可以使用dup2.

#include <unistd.h>
#include <stdio.h>

int main(void) {  

  fprintf(stderr, "This goes to stderr\n");

  dup2(1, 2);  //redirects stderr to stdout below this line.

  fprintf(stderr, "This goes to stdout\n");
}

回答by Jerry Coffin

The normal way would be something like:

正常的方式是这样的:

avrdude -c usbtiny 2>&1

This directs what would normally go to stderr to go to stdout instead. If you'd prefer to direct it to a file, you could do something like:

这会指示通常会转到 stderr 的内容改为转到 stdout。如果您希望将其定向到文件,您可以执行以下操作:

avrdude -c usbtiny 2> outputfile.txt

回答by dreamlax

The following uses the POSIX function to duplicate the standard output file number into the standard error file number. Duplicating stderr to stdout is given in the POSIX page for dup2as an example usage of the function.

下面使用POSIX函数将标准输出文件号复制到标准错误文件号中。POSIX 页面中给出了将 stderr 复制到 stdoutdup2作为该函数的示例用法。

#include <unistd.h>
#include <stdio.h>

int main (void)
{
    pid_t child = fork();

    if (child == 0)
    {
        dup2(STDOUT_FILENO, STDERR_FILENO);
        execlp("avrdude", "-c", "usbtiny", NULL);
    }
    else if (child > 0)
    {
        waitpid(child);
        puts("Done!");
    }
    else
    {
        puts("Error in forking :(");
    }

    return 0;
}

回答by Dummy00001

I need to somehow block the command in C so I can get its stderr

我需要以某种方式阻止 C 中的命令,以便我可以获得它的 stderr

Start by reading man fork, man execon how to start a child process. Look into man 7 signal, man sigactionand man waitfor how to reap the child.

从阅读开始man forkman exec了解如何启动子进程。看看man 7 signalman sigaction以及man wait如何收割孩子。

Finally, the man dup2.

最后,man dup2.

Untested code to exemplify:

未经测试的代码来举例说明:

int pip_stderr[2];
int r;
int pid;

r = pipe(pip_stderr);
assert( r != -1 );

int pid = fork();
assert( pid != -1 );
if (pid == 0) { /* child */
   /* child doesn't need to read from stderr */
   r = close(pip_stderr[0]); assert( r != -1 );
   /* make fd 2 to be the writing end of the pipe */
   r = dup2(pip_stderr[1], 2); assert( r != -1 );
   /* close the now redundant writing end of the pipe */
   r = close(pip_stderr[1]); assert( r != -1 );
   /* fire! */
   exec( /* whatever */ );
   assert( !"exec failed!" );
} else { /* parent */
   /* must: close writing end of the pipe */
   r = close( pip_stderr[1] ); assert( r != -1 );

   /* here read from the pip_stderr[0] */

   r = waitpid(pid,0,0); assert( r == pid );
}

Using dup2() we replace stderr (which is fd 2) of the child with a writing end of a pipe. pipe() is called before fork(). After fork we also have to close all hangingends of the pipe so that the reading in parent process would actually receive EOF.

使用 dup2() 我们用管道的写入端替换孩子的 stderr(即 fd 2)。pipe() 在 fork() 之前被调用。在 fork 之后,我们还必须关闭管道的所有悬挂端,以便父进程中的读取实际上会收到 EOF。

Probably there is a simpler solution using stdio, but I'm not aware of it. Since popen() runs the command via shell, probably one can tell it to redirect stderr to stdout (and send stdout to /dev/null). Never tried that.

可能有一个使用 stdio 的更简单的解决方案,但我不知道。由于 popen() 通过 shell 运行命令,可能可以告诉它将 stderr 重定向到 stdout(并将 stdout 发送到 /dev/null)。从来没有尝试过。

One can also use mktemp() (man 3 mktemp) to create a temp file name, compose command for system() to redirect stderr of the command to the temp file and after system() returns read the temp file.

还可以使用 mktemp() ( man 3 mktemp) 创建临时文件名,为 system() 编写命令以将命令的 stderr 重定向到临时文件,并在 system() 返回后读取临时文件。