hide random home http://www.fmi.uni-passau.de/archive/doc/unix/perl/faq/2.24.html (Einblicke ins Internet, 10/1995)

How can I capture STDERR from an external command?

How can I capture STDERR from an external command?


    There are three basic ways of running external commands:

        system $cmd;
        $output = `$cmd`;
        open (PIPE, "cmd |");

    In the first case, both STDOUT and STDERR will go the same place as
    the script's versions of these, unless redirected.  You can always put
    them where you want them and then read them back when the system
    returns.  In the second and third cases, you are reading the STDOUT
    *only* of your command.  If you would like to have merged STDOUT and
    STDERR, you can use shell file-descriptor redirection to dup STDERR to
    STDOUT:

        $output = `$cmd 2>&1`;
        open (PIPE, "cmd 2>&1 |");

    Another possibility is to run STDERR into a file and read the file 
    later, as in 

        $output = `$cmd 2>some_file`;
        open (PIPE, "cmd 2>some_file |");
    
    Here's a way to read from both of them and know which descriptor
    you got each line from.  The trick is to pipe only STDERR through
    sed, which then marks each of its lines, and then sends that
    back into a merged STDOUT/STDERR stream, from which your Perl program
    then reads a line at a time:

        open (CMD, 
          "3>&1 (cmd args 2>&1 1>&3 3>&- | sed 's/^/STDERR:/' 3>&-) 3>&- |");

        while (<CMD>) {
          if (s/^STDERR://)  {
              print "line from stderr: ", $_;
          } else {
              print "line from stdout: ", $_;
          }
        }

    Be apprised that you *must* use Bourne shell redirection syntax
    here, not csh!  In fact, you can't even do these things with csh.
    For details on how lucky you are that perl's system() and backtick
    and pipe opens all use Bourne shell, fetch the file from convex.com
    called /pub/csh.whynot -- and you'll be glad that perl's shell
    interface is the Bourne shell.

    There's an &open3 routine out there which will be merged with 
    &open2 in perl5 production.