I am experiencing some strange return values from system()
when a child process receives a SIGINT from the terminal. To explain, from a Perl script parent.pl
I used system()
to run another Perl script as a child process, but I also needed to run the child through the shell, so I used the system 'sh', '-c', ...
form.. So the parent of the child became the sh
process and the parent of the sh
process became parent.pl
. Also, to avoid having the sh
process receiving the SIGINT
signal, I trapped it.
For example, parent.pl
:
use feature qw(say);
use strict;
use warnings;
for (1..3) {
my $res = system 'sh', '-c', "trap '' INT; child$_.pl";
say "Parent received return value: " . ($res >> 8);
}
where child1.pl
:
local $SIG{INT} = "DEFAULT";
sleep 10;
say "Child timed out..";
exit 1;
child2.pl
:
local $SIG{INT} = sub { die };
sleep 10;
say "Child timed out..";
exit 1;
and child3.pl
is:
eval {
local $SIG{INT} = sub { die };
sleep 10;
};
if ( $@ ) {
print $@;
exit 2;
}
say "Child timed out..";
exit 0;
If I run parent.pl
(from the command line) and press CTRL-C to abort each child process, the output is:
^CParent received return value: 130
^CDied at ./child2.pl line 7.
Parent received return value: 4
^CDied at ./child3.pl line 8.
Parent received return value: 2
Now, I would like to know why I get a return value of 130 for case 1, and a return value of 4 for case 2.
Also, it would be nice to know exactly what the "DEFAULT"
signal handler does in this case.
Note: the same values are returned if I replace sh
with bash
( and trap SIGINT
instead of INT
in bash
).
See also:
This question is very similar to Propagation of signal to parent when using system that you asked earlier.
From my bash docs:
When a command terminates on a fatal signal N, bash uses the value of 128+N as the exit status.
SIGINT is typically 2, so 128 + 2 give you 130.
Perl's die figures out its exit code by inspecting $!
or $?
for an uncaught exception (so, not the case where you use eval
):
exit $! if $!; # errno
exit $? >> 8 if $? >> 8; # child exit status
exit 255; # last resort
Notice that in this case, Perl exits with the value as is, not shifted up 8 bits.
The errno value happens to be 4 (see errno.h). The $!
variable is a dualvar with different string and numeric values. Use it numerically (like adding zero) to get the number side:
use v5.10;
local $SIG{INT}=sub{
say "numeric errno is ", $!+0;
die
};
sleep 10;
print q(timed out);
exit 1;
This prints:
$ bash -c "perl errno.pl"
^Cnumeric errno is 4
Died at errno.pl line 6.
$ echo $?
4
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With