29

I'm trying to use popen() to catch the stderr of a call, but of course it doesn't seem to be doing that. Any ideas?

My code looks more or less like this:

popen("nedit", "r");

But I'm getting all this garbage about non-utf8 on my screen...

Alexis Wilke
  • 19,179
  • 10
  • 84
  • 156
poy
  • 10,063
  • 9
  • 49
  • 74

3 Answers3

46

popen gives you a file handle on a process' stdout, not its stderr. Its first argument is interpreted as a shell command, so you can do redirections in it:

FILE *p = popen("prog 2>&1", "r");

or, if you don't want the stdout at all,

FILE *p = popen("prog 2>&1 >/dev/null", "r");

(Any other file besides /dev/null is acceptable as well.)

Fred Foo
  • 355,277
  • 75
  • 744
  • 836
4

If you want to discard all of the error messages, then you can use:

popen("nedit 2>/dev/null", "r");
qbert220
  • 11,220
  • 4
  • 31
  • 31
1

if you need both stdout and stderr streams, you can open an extra pipe and redirect child stderr to it:

if (pipe(pfd) < 0)
    return -1;
    
perr = fdopen(pfd[0], "r");

snprintf(command, LINE_LEN, "... 2>&%d", pfd[1]);

if (pout = popen(command, "r")) {
    close(pfd[1]);

    while (fgets(line, LINE_LEN, pout) != NULL)
        ...
    
    while (fgets(line, LINE_LEN, perr) != NULL)
        ...

    pclose(pout);
}

fclose(perr);
close(pfd[0]), close(pfd[1]);

As Andrew pointed out, if command generates lots of output/errors, you must handle the streams more carefully (see comments below).

  • Interesting use of a pipe to capture the error stream from the child process in a separate stream. I don't think reusing `stdout` and `stderr` is a good idea, though, as that makes your implementation unsuitable for general use. And *reading* from them certainly is not a good idea. And you have to be real careful reading from both streams - if the child process fills up the pipe for the stream you're *not* reading from, your two processes will deadlock - you won't get any output from the stream you're trying to read from because the child process is trying to write to the other stream. – Andrew Henle Jun 28 '23 at 00:07
  • Thank you. I edited my response to fix the stream names (pout, perr). With regard to reading the streams: strictly speaking, it would be necessary to use select() to determine which stream needs to be read at each moment. (But that would make the code overly complicated to handle simple situations). – Andre Luis da Silva Monteiro Jun 28 '23 at 20:59