$ perldoc -q stderr Found in /opt/perl/snap/lib/5.8.8/pods/perlfaq8.pod 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 th +e 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 Go +ldberg 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 ST +DERR: 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 te +mp files: use IPC::Open3; use Symbol qw(gensym); use IO::File; local *CATCHOUT = IO::File->new_tmpfile; local *CATCHERR = IO::File->new_tmpfile; 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 followi +ng should work just as well, without deadlocking: use IPC::Open3; use Symbol qw(gensym); use IO::File; local *CATCHERR = IO::File->new_tmpfile; 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 progra +m'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 dupl +icate 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. Th +is 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 STDOU +T). Note that you *must* use Bourne shell (sh(1)) redirection syntax i +n 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 a +rticle in the "Far More Than You Ever Wanted To Know" collection in http://www.cpan.org/misc/olddoc/FMTEYEWTK.tgz . To capture a comma +nd's STDERR and STDOUT together: $output = `cmd 2>&1`; # either with back +ticks $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 back +ticks $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 back +ticks $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 back +ticks $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 ea +siest to redirect them separately to files, and then read from those fil +es 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 sh +ell processes file descriptor redirections in strictly left to right o +rder. 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 th +e temporary file. The second command sends only the old standard out +put there, and the old standard error shows up on the old standard out +.
-- Randal L. Schwartz, Perl hacker
Be sure to read my standard disclaimer if this is a reply.
In reply to Re: catching STDERR of a system(@callout)
by merlyn
in thread catching STDERR of a system(@callout)
by agarsha
| For: | Use: | ||
| & | & | ||
| < | < | ||
| > | > | ||
| [ | [ | ||
| ] | ] |