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

核能气质少年 提交于 2019-11-30 19:26:00

I've not tried something like this in OpenBSD, but in at least a few *nix-like systems, you can do this using 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");
}

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:

avrdude -c usbtiny 2> outputfile.txt

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 dup2 as an example usage of the function.

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

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

Start by reading man fork, man exec on how to start a child process. Look into man 7 signal, man sigaction and man wait for how to reap the child.

Finally, the 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 hanging ends of the pipe so that the reading in parent process would actually receive 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.

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.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!