pattyj has asked for the wisdom of the Perl Monks concerning the following question:

I've been googling for a while now and can't find a simple example which makes me think "aha! this is a good way to do it!"

Here is my predicament:

 ./somebinary | ./myscript.pl

I'd like myscript.pl to capture the output from the run of somebinary, as well as the exit code.

The output is easy enough, but the exit code seems very elusive. In pure bash I would fiddle around with $PIPESTATUS, but I'd like the perl way of doing this. A nice perl way of doing it.

  • Comment on Capturing the stdout and exit code from a program piped to perl

Replies are listed 'Best First'.
Re: Capturing the stdout and exit code from a program piped to perl
by LanX (Saint) on Dec 09, 2014 at 11:50 UTC
    I suppose you need a way to do it from commandline.

    I'd pass the path of the binary to the script

    ./myscript.pl ./somebinary

    like this Perl has the path to be called in $ARGV[0] and can capture the exit code and STDOUT and STDERR.

    Cheers Rolf

    (addicted to the Perl Programming Language and ☆☆☆☆ :)

    update

    try either

    my $path = $ARGV[0]; open my $fh, "-|", "$path 2>&1" or die "can't open $path: $!"; print ": $_" for <$fh>; # print line by line close $fh;

    or

    my $x= `$path 2>&1`; print "<<< $x >>>"; # print whole slurp

    the 2>&1 part redirects STDERR to STDOUT.

    update

    print ": exitcode" , $? >>8; will show the exitcode (see perlvar )

    update

    all in all a bit fiddly, maybe the modules AnoMonk suggested are more reliable.

Re: Capturing the stdout and exit code from a program piped to perl
by Anonymous Monk on Dec 09, 2014 at 11:23 UTC

    Run "somebinary" either in myscript.pl itself, or a Perl wrapper around both, to get the exit code besides the output. Search for pipe related documentation; some of which are IPC::Run & IPC::Open3.

      Dang! perldoc.org link of IPC::Run is bad; try CPAN one: IPC::Run.

        Double Dang! I should have written only "perldoc" as the host actually is "perldoc.perl.org".
Re: Capturing the stdout and exit code from a program piped to perl
by Laurent_R (Canon) on Dec 09, 2014 at 21:46 UTC
    One possible way to capture both command output and shell return code is to call the shell a second time. Example of success:
    $ perl -E ' @c = `ls f*.*`; $return_code = `echo $?`; say scalar $ret +urn_code;' 0
    Example of failure:
    $ perl -E ' @c = `ls foobar.*`; $return_code = `echo $?`; say scalar +$return_code;' ls: impossible to find foobar.*: No such file or directory 512
    Or something somewhat more similar to what you have:
    $ ls *.* | sort | perl -E '@c = <>; say scalar @c, " files"; $return_ +code = `echo $?`; say scalar $return_code;' 294 files 0

    Update @ 21:57 UTC: This last syntax does not seem to work properly. It seems that piping the result to the Perl process leads to the loss of the $? value of the initial process (well, or maybe it is more accurate to say that the child process forked by the pipe does not know about the status of the initial process). I get a 0 return code even when the initial command fails:

    $ ls foobar.* | perl -E ' $return_code = `echo $?`; say scalar $retu +rn_code;' ls: impossible to find foobar.*: No such file or directory 0
    Sorry if this last part of my answer turned out not to be very useful. The first part of my answer still gives you a possible way to go: you can call ./somebinary with back quotes from your Perl script and recover both the output and the return code.
      Laurent_R, on what kind of system did you try the ls | perl command? I ask for impossible to find in ls error message is new to me (have not seen yet on FreeBSD 4.x to 8.4-STABLE, Redhat CentOS 5, 6).
        Hi, I tried it on Cygwin (linux/bash emulator under Windows) and AIX (IBM's brand of Unix). This is the message under AIX:
        ls foobar.* | perl -E ' $return_code = `echo $?`; say scalar $return +_code;' ls: cannot access foobar.*: A file or directory in the path name does +not exist. 0
        Well, now that I think about it, I translated into English the original message, to make it clearer to the English-speaking reader.