FAQ 8.25 How can I capture STDERR from an external command?



This message is one of several periodic postings to comp.lang.perl.misc
intended to make it easier for perl programmers to find answers to
common questions. The core of this message represents an excerpt
from the documentation provided with Perl.

--------------------------------------------------------------------

8.25: How can I capture STDERR from an external command?

There are three basic ways of running external commands:

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

With system(), both STDOUT and STDERR will go the same place as the
script's STDOUT and STDERR, unless the system() command redirects them.
Backticks and open() read only the STDOUT of your command.

You can also use the open3() function from IPC::Open3. Benjamin Goldberg
provides some sample code:

To capture a program's STDOUT, but discard its STDERR:

use IPC::Open3;
use File::Spec;
use Symbol qw(gensym);
open(NULL, ">", File::Spec->devnull);
my $pid = open3(gensym, \*PH, ">&NULL", "cmd");
while( <PH> ) { }
waitpid($pid, 0);

To capture a program's STDERR, but discard its STDOUT:

use IPC::Open3;
use File::Spec;
use Symbol qw(gensym);
open(NULL, ">", File::Spec->devnull);
my $pid = open3(gensym, ">&NULL", \*PH, "cmd");
while( <PH> ) { }
waitpid($pid, 0);

To capture a program's STDERR, and let its STDOUT go to our own STDERR:

use IPC::Open3;
use Symbol qw(gensym);
my $pid = open3(gensym, ">&STDERR", \*PH, "cmd");
while( <PH> ) { }
waitpid($pid, 0);

To read both a command's STDOUT and its STDERR separately, you can
redirect them to temp files, let the command run, then read the temp
files:

use IPC::Open3;
use Symbol qw(gensym);
use IO::File;
local *CATCHOUT = IO::File->new_tempfile;
local *CATCHERR = IO::File->new_tempfile;
my $pid = open3(gensym, ">&CATCHOUT", ">&CATCHERR", "cmd");
waitpid($pid, 0);
seek $_, 0, 0 for \*CATCHOUT, \*CATCHERR;
while( <CATCHOUT> ) {}
while( <CATCHERR> ) {}

But there's no real need for *both* to be tempfiles... the following
should work just as well, without deadlocking:

use IPC::Open3;
use Symbol qw(gensym);
use IO::File;
local *CATCHERR = IO::File->new_tempfile;
my $pid = open3(gensym, \*CATCHOUT, ">&CATCHERR", "cmd");
while( <CATCHOUT> ) {}
waitpid($pid, 0);
seek CATCHERR, 0, 0;
while( <CATCHERR> ) {}

And it'll be faster, too, since we can begin processing the program's
stdout immediately, rather than waiting for the program to finish.

With any of these, you can change file descriptors before the call:

open(STDOUT, ">logfile");
system("ls");

or you can use Bourne shell file-descriptor redirection:

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

You can also use file-descriptor redirection to make STDERR a duplicate
of STDOUT:

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

Note that you *cannot* simply open STDERR to be a dup of STDOUT in your
Perl program and avoid calling the shell to do the redirection. This
doesn't work:

open(STDERR, ">&STDOUT");
$alloutput = `cmd args`; # stderr still escapes

This fails because the open() makes STDERR go to where STDOUT was going
at the time of the open(). The backticks then make STDOUT go to a
string, but don't change STDERR (which still goes to the old STDOUT).

Note that you *must* use Bourne shell (sh(1)) redirection syntax in
backticks, not csh(1)! Details on why Perl's system() and backtick and
pipe opens all use the Bourne shell are in the versus/csh.whynot article
in the "Far More Than You Ever Wanted To Know" collection in
http://www.cpan.org/misc/olddoc/FMTEYEWTK.tgz . To capture a command's
STDERR and STDOUT together:

$output = `cmd 2>&1`; # either with backticks
$pid = open(PH, "cmd 2>&1 |"); # or with an open pipe
while (<PH>) { } # plus a read

To capture a command's STDOUT but discard its STDERR:

$output = `cmd 2>/dev/null`; # either with backticks
$pid = open(PH, "cmd 2>/dev/null |"); # or with an open pipe
while (<PH>) { } # plus a read

To capture a command's STDERR but discard its STDOUT:

$output = `cmd 2>&1 1>/dev/null`; # either with backticks
$pid = open(PH, "cmd 2>&1 1>/dev/null |"); # or with an open pipe
while (<PH>) { } # plus a read

To exchange a command's STDOUT and STDERR in order to capture the STDERR
but leave its STDOUT to come out our old STDERR:

$output = `cmd 3>&1 1>&2 2>&3 3>&-`; # either with backticks
$pid = open(PH, "cmd 3>&1 1>&2 2>&3 3>&-|");# or with an open pipe
while (<PH>) { } # plus a read

To read both a command's STDOUT and its STDERR separately, it's easiest
to redirect them separately to files, and then read from those files
when the program is done:

system("program args 1>program.stdout 2>program.stderr");

Ordering is important in all these examples. That's because the shell
processes file descriptor redirections in strictly left to right order.

system("prog args 1>tmpfile 2>&1");
system("prog args 2>&1 1>tmpfile");

The first command sends both standard out and standard error to the
temporary file. The second command sends only the old standard output
there, and the old standard error shows up on the old standard out.



--------------------------------------------------------------------

Documents such as this have been called "Answers to Frequently
Asked Questions" or FAQ for short. They represent an important
part of the Usenet tradition. They serve to reduce the volume of
redundant traffic on a news group by providing quality answers to
questions that keep coming up.

If you are some how irritated by seeing these postings you are free
to ignore them or add the sender to your killfile. If you find
errors or other problems with these postings please send corrections
or comments to the posting email address or to the maintainers as
directed in the perlfaq manual page.

Note that the FAQ text posted by this server may have been modified
from that distributed in the stable Perl release. It may have been
edited to reflect the additions, changes and corrections provided
by respondents, reviewers, and critics to previous postings of
these FAQ. Complete text of these FAQ are available on request.

The perlfaq manual page contains the following copyright notice.

AUTHOR AND COPYRIGHT

Copyright (c) 1997-2002 Tom Christiansen and Nathan
Torkington, and other contributors as noted. All rights
reserved.

This posting is provided in the hope that it will be useful but
does not represent a commitment or contract of any kind on the part
of the contributers, authors or their agents.
.



Relevant Pages

  • FAQ 8.25 How can I capture STDERR from an external command?
    ... This message is one of several periodic postings to comp.lang.perl.misc ... both STDOUT and STDERR will go the same place as the ... script's STDOUT and STDERR, unless the systemcommand redirects them. ... You can also use file-descriptor redirection to make STDERR a duplicate ...
    (comp.lang.perl.misc)
  • FAQ 8.25 How can I capture STDERR from an external command?
    ... This message is one of several periodic postings to comp.lang.perl.misc ... both STDOUT and STDERR will go the same place as the ... script's STDOUT and STDERR, unless the systemcommand redirects them. ... You can also use file-descriptor redirection to make STDERR a duplicate ...
    (comp.lang.perl.misc)
  • FAQ 8.25 How can I capture STDERR from an external command?
    ... both STDOUT and STDERR will go the same place as the ... script's STDOUT and STDERR, unless the systemcommand redirects them. ... You can also use file-descriptor redirection to make STDERR a duplicate ... The first command sends both standard out and standard error to the ...
    (comp.lang.perl.misc)
  • FAQ 8.25 How can I capture STDERR from an external command?
    ... both STDOUT and STDERR will go the same place as the ... script's STDOUT and STDERR, unless the systemcommand redirects them. ... You can also use file-descriptor redirection to make STDERR a duplicate ... The first command sends both standard out and standard error to the ...
    (comp.lang.perl.misc)
  • FAQ 8.25 How can I capture STDERR from an external command?
    ... both STDOUT and STDERR will go the same place as the ... script's STDOUT and STDERR, unless the systemcommand redirects them. ... You can also use file-descriptor redirection to make STDERR a duplicate ... The first command sends both standard out and standard error to the ...
    (comp.lang.perl.misc)