Beefy Boxes and Bandwidth Generously Provided by pair Networks
There's more than one way to do things

Capturing both STDOUT, STDERR and exit status

by pbeckingham (Parson)
on May 06, 2005 at 16:04 UTC ( #454715=perlquestion: print w/replies, xml ) Need Help??
pbeckingham has asked for the wisdom of the Perl Monks concerning the following question:

I would like to run an external command, and capture the STDOUT, STDERR and the exit status of that command. This will run on *nix, so for example, I can do this:

my $status = system '/bin/ls / > /tmp/output 2>&1';
This will give me the exit status, and allow me to slurp the output. But I am wondering if anyone knows a way for me to do both at the same time. If only IPC::Open3 gave me a way to capture the exit status.

pbeckingham - typist, perishable vertebrate.

Replies are listed 'Best First'.
Re: Capturing both STDOUT, STDERR and exit status
by merlyn (Sage) on May 06, 2005 at 16:13 UTC
Re: Capturing both STDOUT, STDERR and exit status
by polettix (Vicar) on May 06, 2005 at 16:31 UTC
    A backtick/qx suffices to mimic what you already do:
    my $alloutput = qx(/bin/ls / 2>&1); my $exitcode = $? >> 8;
    If you need to keep stderr and stdout separate use merlyn's suggestion.

    Flavio (perl -e 'print(scalar(reverse("\nti.xittelop\@oivalf")))')

    Don't fool yourself.

      Thanks, this is nice and clean. I did make the qx output scalar, otherwise it gives me a list of output lines.

      sub executeCommand { my $command = join ' ', @_; ($? >> 8, $_ = qx{$command 2>&1}); } my ($status, $output) = executeCommand ('/bin/ls', '/');

      pbeckingham - typist, perishable vertebrate.
        You have to reverse the return list, otherwise you'll refer to the previous value of $?:
        sub executeCommand_wrong { my $command = join ' ', @_; ($? >> 8, $_ = qx{$command 2>&1}); } sub executeCommand_correct { my $command = join ' ', @_; ($_ = qx{$command 2>&1}, $? >> 8); } my $command = 'echo -n ciao ; false'; my ($status, $output) = executeCommand_wrong ($command); print "[$output] -> [$status]\n"; ($output, $status) = executeCommand_correct($command); print "[$output] -> [$status]\n"; __END__ [ciao] -> [0] [ciao] -> [1]
        If you cannot live without having $status as the first returned value, just use reverse:
        sub executeCommand { my $command = join ' ', @_; reverse ($_ = qx{$command 2>&1}, $? >> 8); }

        Flavio (perl -e 'print(scalar(reverse("\nti.xittelop\@oivalf")))')

        Don't fool yourself.
Re: Capturing both STDOUT, STDERR and exit status
by zentara (Archbishop) on May 06, 2005 at 16:40 UTC
    Heres an example. You can also use select on the filehandles.
    #!/usr/bin/perl use warnings; use strict; use IPC::Open3; my $cmd = 'ls -la'; my $pid = open3(\*WRITER, \*READER, \*ERROR, $cmd); #if \*ERROR is 0, stderr goes to stdout while( my $output = <READER> ) { print "output->$output"; } while( my $errout = <ERROR> ) { print "err->$errout"; } waitpid( $pid, 0 ) or die "$!\n"; my $retval = $?; print "retval-> $retval\n";

    I'm not really a human, but I play one on earth. flash japh
      (hopefully not being too much of a thread necrophile here) This is an excellent example, which has just saved me from abhorrent temp file hell. One small quibble; the retval line should probably read:
      my $retval = $? >> 8;
Re: Capturing both STDOUT, STDERR and exit status
by saintmike (Vicar) on May 10, 2005 at 17:54 UTC
    Sysadm::Install provides a function for that:
    use Sysadm::Install qw(tap); my($stdout, $stderr, $rc) = tap "/bin/ls", "-l", "foobar"; print "stdout=$stdout\n", "stderr=$stderr\n", "rc=$rc\n";

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://454715]
Approved by Old_Gray_Bear
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others taking refuge in the Monastery: (7)
As of 2017-07-25 05:44 GMT
Find Nodes?
    Voting Booth?
    I came, I saw, I ...

    Results (363 votes). Check out past polls.