in reply to SIGINT in system() with shell metachars

An addendum: (BTW, I'm running in Solaris8.) After posting this, I ran yet more tests, and discovered that when I run system() with just one argument, thus invoking shell interpolation, the return code from system() is reorganized.

Programming Perl (page 812) describes the system() return value as follows (for system with a LIST argument):

$exit_value = $? >> 8; $signal_num = $? & 127; # or 0x7f ... $dumped_core = $? & 128; # or 0x80 ...

I.e. the return status is in the HIGH byte, and the signal received, and coredump status, are encoded in the LO byte.

But in the single argument form of system(), I notice that the LO byte has nothing in it. The HIGH byte seems to be encoded as follows:

$high_byte = $? >> 8; $was_interrupted = $high_byte & 0x80; $status = $high_byte & 0x7f;
If $was_interrupted is 0, then $status is the return status of the shell command. If $was_interrupted is 1, then $status is the signal number that interrupted the child shell.

I'm posting this because I haven't seen this documented anywhere. Does anyone know this stuff already? Where (if at all) is this documented? Is this a Solaris feature, or a Perl feature??

thanks!
-cadphile

Replies are listed 'Best First'.
Re: SIGINT in system() with shell metachars
by Abigail-II (Bishop) on Jun 25, 2003 at 00:58 UTC
    You should realize that with the single argument form of system(), the shell may be called and passed the argument string (whether or not it's called depends on the content of the string, and also on the OS). If the shell is called, you will get back the exit status of the shell - not the exit status of the program(s) mentioned in the argument string (after all, Perl calls the shell if Perl finds the argument string to complex to deal with it, so Perl doesn't know what is eventually called). What the shell will return might be platform dependend.

    Abigail

Re: Re: SIGINT in system() with shell metachars
by andrewc (Acolyte) on Jun 25, 2003 at 13:36 UTC

    This is probably a POSIX-only feature, but I might be wrong - you probably won't see signals at all on other systems. If you do happen to be in a Unixy environment -- Linux, Solaris, *BSD, et al. -- the following should probably do what you want:

    #!/usr/bin/perl use POSIX qw{:signal_h}; if (system('for a in 1 2 3 4; do echo $a>>/tmp/foobar; echo tick $a; s +leep 5; done') != 0) { my $sig_if_any = $? & 127; my $return_value = $? >> 8; print "child died: rv=$return_value, signal=$sig_if_any\n"; if (defined($sig_if_any) && ($sig_if_any == SIGINT)) { print "child was interrupted\n"; # ... do something appropriate ... } # ... cleanup ... } else { # ... do something with /tmp/foobar } ## ... run, and hit ctrl-c while it ticks...

    The usual caveats about interpolating Perl variables into the strings passed to system() apply, of course :). Any monks more cross-platformy than me care to comment on the applicability of $? on other systems?