How do I check the status of the first program in a pipeline in a Perl () system?
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.
source to share
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.
source to share
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.
source to share
[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 ].
source to share
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.
source to share
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 andperl
* 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).
- subshell * exec () * s
-
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)
source to share