C:如何将stderr从System-command重定向到stdout或文件?

时间:2010-06-11 01:26:38

标签: c stdout stderr file-descriptor

shell命令$ avrdude -c usbtiny将文本输出到stderr。我无法通过诸如head-less-more之类的命令来阅读它。它不是stdout。我想要文本stdout或文件。我怎么能用C做呢?我试图通过my last question解决问题,但仍未解决。

4 个答案:

答案 0 :(得分:16)

我在OpenBSD中没有尝试过这样的东西,但至少在类似* nix的系统中,你可以使用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");
}

答案 1 :(得分:3)

正常的方式是:

avrdude -c usbtiny 2>&1

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

avrdude -c usbtiny 2> outputfile.txt

答案 2 :(得分:0)

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

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

答案 3 :(得分:-1)

  

我需要以某种方式阻止C中的命令,这样我才能得到它的stderr

首先阅读man forkman exec,了解如何启动子流程。查看man 7 signalman sigactionman wait,了解如何收获孩子。

最后,man dup2

未经测试的代码示例:

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

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

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

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