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.
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 escapesThis 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/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 readTo 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 readTo 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 readTo 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 readTo read both a command's STDOUT and its STDERR separately, it's easiest
and safest to redirect them separately to files, and then read from those
files when the program is done:
system("program args 1>/tmp/program.stdout 2>/tmp/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.