How do I check the status of the first program in a pipeline in a Perl () system?

perl -e 'system ("crontab1 -l");print $?'

      

returns -1 as expected (program crontab1 does not exist)

perl -e 'system ("crontab1 -l|grep blah");print $?'

      

returns 256.

What is the way to check the status of the first (or both) programs?

+2


source to share


7 replies


You get the exit status of the entire team, as you would expect. If you want to get the exit status separately, you will have to run the commands separately.

#!/usr/bin/perl -e
system("crontab1 -l > /tmp/junk.txt"); print $?;
system("grep blah /tmp/junk.txt"); print $?;

      



as an example.

+4


source


If you tolerate using anything other than system

, there are easier solutions. For example, the method results

in IPC :: Run
returns all exit codes from the chain.



+4


source


Remember you have to use $? β†’ 8 to get the exit code, not $?

perl -e 'system("set -o pipefail;false | true");print $?>>8,"\n"'

      

1

This ("pipefail") only works if your shell is bash 3. Cygwin and linux ship with it; not sure about mac.

You should be aware that 256 is an error return. 0 is what you get from success:

perl -e 'system("true");print $?>>8,"\n"'

      

0

I didn't know that the system returned -1 for the only command not found, but in this case $? β†’ 8 will still be nonzero.

+3


source


[This was written as an answer to another question which has been closed as a duplicate of this.]

Executing a shell command requires executing a shell. To this end

system($shell_command)

      

equivalent to

system('/bin/sh', '-c', $shell_command)

      

This way, all of your examples run one program ( /bin/sh

). If you want exit statuses from multiple children, you need multiple children!

use IPC::Open3 qw( open3 );

open(local *CHILD1_STDIN, '<', '/dev/null')
   or die $!;

pipe(local *CHILD2_STDIN, local *CHILD1_STDOUT)
   or die $!;

my $child1_pid = open3(
   '<&CHILD1_STDIN',
   '>&CHILD1_STDOUT',
   '>&STDERR',
   'prog1', 'arg1', 'arg2',
);

my $child2_pid = open3(
   '<&CHILD2_STDIN',
   '>&STDOUT',
   '>&STDERR',
   'prog2', 'arg1', 'arg2',
);

my @pipe_status = map { waitpid($_, 0) } $child1_pid, $child2_pid;

      

IPC :: Open3 is pretty low level. IPC :: Run3 and / or IPC :: Run can make this easier. [Update: indeed, IPC :: Run does ].

+2


source


If you want to check the status, do not put them on the same system. Open the read channel of the first program to receive its output, then open another channel for another program.

+1


source


The operating system only returns an exit status for the last executed program, and if the OS does not return it, perl will not be able to report it.

I don't know how to get the exit code returned by earlier programs in a pipeline other than running each one separately and using temporary files instead of pipes.

+1


source


What is the way to check the status of the first (or both) programs?

There is no such way, at least not the way you created things. You may have to manage the subprocesses yourself with fork (), exec () and waitpid () if you must know these things.

This is roughly what happens in your code snippet.

  • perl

    system () starts the shell and perl

    * wait () * s to terminate this subprocess.

  • The shell sets up the pipeline:

    • subshell * exec () * s grep

      at the read end of the pipe
    • the subshell doesn't find crontab1

      anywhere $PATH

      and * exit () * s 127 (on my system, i.e. where 127 is a shell indicating a failure to find a program to run).
  • grep

    detects end of file on its input and, without comparing anything, * exit () * s 1.

  • A shell * exit () * s with the exit code of the last process in the pipeline, which, again, is 1.

  • perl

    detects shell exit code 1, which is encoded in $?

    as 256.
    (256 -> 8 == 1)

+1


source







All Articles