http://www.perlmonks.org?node_id=546749

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

This little failing test case illustrates my question:
# Test error checking for piped system calls # We use 'boom', a non-existent command, for testing. use Test::More qw/no_plan/; use strict; ok_system_call("true"); ok_system_call("true|true"); not_ok_system_call("boom"); not_ok_system_call("boom|boom"); not_ok_system_call("true|boom"); not_ok_system_call("boom|true"); #################################3 sub ok_system_call { my $test = shift; my $expect_success = shift; $expect_success = 1 if not defined $expect_success; my $ok = (system($test) == 0); # my $exit_code = $? >> 8; # diag "exit code was: $exit_code"; return $expect_success ? ok($ok, $test) : ok(!$ok, $test); } sub not_ok_system_call { my $test= shift; return ok_system_call($test,0); }
The error checking doesn't work correctly on the last one ("boom|true"), so it fails. I believe this happens because although boom fails, something is sent through the pipe, and 'true' succeeds on the other end of the pipe. What's the best practicing for error checking a piped command so this case is covered?
  • Comment on best practices for checking system return values for piped commands?
  • Download Code

Replies are listed 'Best First'.
Re: best practices for checking system return values for piped commands?
by Hue-Bond (Priest) on May 01, 2006 at 20:17 UTC
    The error checking doesn't work correctly on the last one ("boom|true"), so it fails. I believe this happens because although boom fails, something is sent through the pipe, and 'true' succeeds on the other end of the pipe.

    On a Linux 2.6, with a bash shell:

    $ boom|true; echo $? bash: boom: command not found 0 $ _

    This is because, according to the documentation of my shell, The return status of a pipeline is the exit status of the last command, unless the pipefail option is enabled. So, if your shell works like bash in this respect, your tests are returning the results they should.

    --
    David Serrano

Re: best practices for checking system return values for piped commands?
by Anonymous Monk on May 02, 2006 at 01:35 UTC
    Note that bash also has a PIPESTATUS (sp?) env var array that allows you to get the "$?" of the intermediate commands in the pipeline.
      I second the use of bash-es PIPESTATUS, I've used it in code like this:
      my %cmds = ( 'bash' => '/usr/local/bin/bash',
                   'gzip' => '/usr/bin/gzip',
                   'lzop' => '/usr/bin/lzop',
                   'wc'   => '/usr/bin/wc' );
      
      
      my @zip_results = `$cmds{'bash'} -c '$cmds{$compress} -dc $file | $cmds{'wc'} -c ; echo \${PIPESTATUS\@}'`;
      
      The last line of @zip_results has the status of both the 'compress' command and the 'wc' command.
        I'm struggling with trying to identify a failure in a set of piped commands run on a remote host via ssh. I use perl to build and run the command line as below
        ssh $TARGET_HOST "sudo find $TARGET_DIR -name \'$TARGET_FILE\' | sudo +cpio --create --format ustar" | bzip2 -9 -c
        Initially I just redirected the output to a file, which is fine if both the $TARGET_DIR and $TARGET_FILE exists. However, if one or both do not exist, then I still get a file created, but it's empty.
        Things I've tried:
        With $ret=system($cmd); and testing the the value of $ret:
      • Pre-fixing the cmd with set -o pipefail &&.
      • Adding set -o pipefail to the command run by ssh.
      • Adding set -o pipefail to the command run by sudo.
      • Doing the bzip2 locally.
        With @results = `$cmd`, and testing the value of $?:
      • Adding ; echo \${PIPESTATUS\@}; to the end of $cmd, within the string passed to ssh.
      • Adding ; echo \${PIPESTATUS\@}; to the end of $cmd, after the string passed to ssh.
        Using the @results approach, I only get one entry, so I suspect that the backtick method only sees one stream?

        Any ideas on how I can detect the remote pipeline failure?
Re: best practices for checking system return values for piped commands?
by billh (Pilgrim) on May 02, 2006 at 12:39 UTC
    Just to add a little to what others have said, 'true' is not the best possible choice for a 2nd command since:
    1. it isn't reading it's stdin in so won't detect anything wrong.
    2. 'true' tries its hardest to live up to its name, always exiting with status zero.
    Bill H
    perl -e 'print sub { "Hello @{[shift]}!\n" }->("World")'

      "true" is a great choice to illustrate my test, as it is a great example of an utility which "succeeds" even with no input piped to it.