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

How to know the status of a command invoked by open function?
When running the following script, I get an unexpected result!

open(PS,"ls . 2>/dev/null|") or die "$!";


close PS;


$t = $?>>8;


print "$t","\n";



# perl openclose.pl
141  #this should be 0 as the command execution is succesful
  • Comment on How to know the status of a command invoked by open function?

Replies are listed 'Best First'.
Re: How to know the status of a command invoked by open function?
by ikegami (Patriarch) on Aug 16, 2011 at 00:31 UTC
    What makes you think execution was successful? Like Perl is telling you, it wasn't successful. You closed its STDOUT before it was done writing to it.

    Update: I figured out why 141. It's (1<<7)|SIGPIPE. This is the shell letting the parent know how its kid exited.

    # No shell involved, and the child died from SIGPIPE: $ perl -e'open(PS,"ls . |") or die "$!"; close PS or die $!; printf("% +04X\n", $?);' 000D # The shell relaying how its child died via its exit code: $ perl -e'open(PS,"ls . 2>/dev/null |") or die "$!"; close PS or die $ +!; printf("%04X\n", $?);' 8D00
      Thanks.
      
      But how can i get the exit status for the command in this case?
      open(PS,"ls . 2>/dev/null |")
      
      why the following two opens have different result?
      open(PS,"ls .|")
      open(PS,"ls . 2>/dev/null |")
      
      Thanks
      James

        [ Please don't use <pre>...</pre>. Use <p> at the start of paragraphs and use <c>...</c> around computer text (code, data, output, etc). ]

        why the following two opens have different result?

        open(PS,"ls . 2>/dev/null |")
        is equivalent to
        open(PS, '-|', /bin/sh', '-c', 'ls . 2>/dev/null ')
        but
        open(PS,"ls . |")
        get optimised to
        open(PS, '-|', 'ls', '.')

        Also see the update to my original reply.

        But how can i get the exit status for the command in this case?

        You already know how. It's in $? after a successful close. In this case, it's 141. The shell returns 141 (128|SIGPIPE) when its child dies from SIGPIPE.

Re: How to know the status of a command invoked by open function?
by tchrist (Pilgrim) on Aug 16, 2011 at 02:50 UTC
    Just depends which command you want the exit status of. It’s quite easy with just one command, as others have shown you, and it’s only slightly trickier with getting the exit status from a command in a pipeline that isn’t the last such command.

    For example, this runs dd to get some output while filtering out some stuff you don’t want with egrep, yet still manages to give you the dd exit status instead of the egrep one:

    $dd_command = <<'EO_COMMAND'; device=/dev/rmt8 dd_noise='^[0-9]+\+[0-9]+ records (in|out)$' exec 3>&1 status=`((dd if=$device ibs=64k 2>&1 1>&3 3>&- 4>&-; echo $? >&4) | egrep -v "$dd_noise" 1>&2 3>&- 4>&-) 4>&1` exit $status; EO_COMMAND @dd_output = `$dd_command`; $status = ($? >> 8); $signo = ($? & 127); $cored = ($? & 128);

    Of course the problem there is you can’t read as you go, so to do that via a pipe, do this:

    $dd_command = <<'EO_COMMAND'; device=/dev/rmt8 dd_noise='^[0-9]+\+[0-9]+ records (in|out)$' exec 3>&1 status=`((dd if=$device ibs=64k 2>&1 1>&3 3>&- 4>&-; echo $? >&4) | egrep -v "$dd_noise" 1>&2 3>&- 4>&-) 4>&1` exit $status; EO_COMMAND $kidpid = open(DD_PIPE, "$dd_command |") // die $!; while (<DD_PIPE>) { # blah blah blah; } close(DD_PIPE); $status = ($? >> 8); $signo = ($? & 127); $cored = ($? & 128);
    If those weren’t obvious, this is simpler:
    $kidpid = open(FROM_KID, "somecmd 3>&1 1>&2 2>&3 3>&- |") // die $!;
    The status//signo/cored bits will be the same, but this lets you concentrate on your three‐ball juggle. The short story is that’s more clearly read as:
    $fd3 = $fd1; $fd1 = $fd2; $fd2 = $fd3; $fd3 = undef;
    Now to use that knowledge in the earlier examples, just throw a fourth ball up into the air.

    Easy as pi!

    //GO.SYSIN DD *, DOODAH, DOODAH

Re: How to know the status of a command invoked by open function?
by toolic (Bishop) on Aug 16, 2011 at 00:51 UTC
Re: How to know the status of a command invoked by open function?
by perl.j (Pilgrim) on Aug 16, 2011 at 00:15 UTC
    Please use tags in your next posts (or just update this one). This will make it easier for everyone to read.
    --perl.j
Re: How to know the status of a command invoked by open function?
by Anonymous Monk on Aug 16, 2011 at 00:36 UTC

    this should be 0 as the command execution is succesful

    The fine manual says you should only check $! (or $?) after a system call fails

    open ... or die $!; close ... or die $!; print ... or die $!;
    Its the only time the value of $!/$? is meaningful
      No. $? is only meaningful if the system call succeeds in this case, and it's always meaningful after wait, waitpid, system and backticks.
        See this from Perl.The.Complete.Reference.2nd.Edition.2001
        
        The close function, on the other hand, picks up any errors generated by
        the executed process because it monitors the return value received from the child
        process via wait (see the “Creating Child Processes” section, later in this chapter).
        I know what the meaning of $?. but for my case. I used open to run an external program