【问题标题】:C: how to redirect stderr from System-command to stdout or file?C:如何将标准错误从系统命令重定向到标准输出或文件?
【发布时间】:2010-06-11 01:26:37
【问题描述】:

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

【问题讨论】:

    标签: c stdout stderr file-descriptor


    【解决方案1】:

    我没有在 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");
    }
    

    【讨论】:

    • 还有两个类似的答案,但出于某种原因,他们似乎认为您需要 fork 才能使用 dup2。
    【解决方案2】:

    正常的方式是这样的:

    avrdude -c usbtiny 2>&1
    

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

    avrdude -c usbtiny 2> outputfile.txt
    

    【讨论】:

    • @user355926:在什么平台上?该标准并未涵盖这一点,因此您需要一些不可移植的代码才能在 C 中完成。
    • 我需要以某种方式阻止 C 中的命令,以便获得它的标准错误
    【解决方案3】:

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

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

    【讨论】:

      【解决方案4】:

      我需要以某种方式阻止 C 中的命令,以便获得它的标准错误

      首先阅读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)替换为管道的写入端。 pipe() 在 fork() 之前调用。在 fork 之后,我们还必须关闭管道的所有 hanging 端,以便父进程中的读取实际上会收到 EOF。

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

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

      【讨论】:

        猜你喜欢
        • 2020-11-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-05-26
        • 2012-11-23
        • 2012-08-15
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多