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

Dear All,

I have a strange problem I am calling a perl script from another perl script using the system command.

The called perl script can exit with different values which I want to capture in the calling script. This works fine unless the called script is interrupted by ctrl-c (although I have accounted for this), instead of getting -2 (as shown below) I get 1 returned??

Any advice much appreciated.

Mags

Here is sample of my code:

####### # calling.pl eval { system ("called.pl"); }; $exit_val = $? >> 8; ####### # called.pl $SIG{INT} = \&exit_gracefully; main block ... $exit_value = 0; exit $exit_value; sub exit_gracefully { $SIG{INT} = \&exit_gracefully; print "Program interrupted .. \n"; exit (-2); }

Janitored by Arunbear - added code tags

Replies are listed 'Best First'.
Re: exit value not passed back
by PodMaster (Abbot) on Oct 06, 2004 at 10:38 UTC
    My test program
    if( @ARGV ){ $SIG{INT} = \&exit_gracefully; for(1..10){ warn "called sleeping $_"; select undef, undef, undef, 0.5; } exit 1; } else { warn "calling system\n"; system ( $^X, __FILE__ , 'called'); $exit_val = $? >> 8; warn "\n exit_val $exit_val"; } sub exit_gracefully { $SIG{INT} = \&exit_gracefully; print "@ARGV Program interrupted .. \n"; exit (2); } __END__
    On perl v5.8.4 built for MSWin32-x86-multi-thread under cmd.exe (Windows XP SP1a), it looks as though calling.pl gets interrupted and then delivers a SIGINT to called.pl.
    C:\>perl \dev\loose\perlfunc.exit.pl calling system called sleeping 1 at \dev\loose\perlfunc.exit.pl line 4. called sleeping 2 at \dev\loose\perlfunc.exit.pl line 4. called sleeping 3 at \dev\loose\perlfunc.exit.pl line 4. called sleeping 4 at \dev\loose\perlfunc.exit.pl line 4. called sleeping 5 at \dev\loose\perlfunc.exit.pl line 4. Terminating on signal SIGINT(2) C:\>called Program interrupted .. C:\>
    On perl v5.8.4 built for i386-linux-thread-multi under bash, I get results as expected
    user@host:~$ perl perlfunc.exit.pl calling system called sleeping 1 at perlfunc.exit.pl line 4. called sleeping 2 at perlfunc.exit.pl line 4. called sleeping 3 at perlfunc.exit.pl line 4. called sleeping 4 at perlfunc.exit.pl line 4. called Program interrupted .. exit_val 2 at perlfunc.exit.pl line 14. user@host:~$ user@host:~$

    MJD says "you can't just make shit up and expect the computer to know what you mean, retardo!"
    I run a Win32 PPM repository for perl 5.6.x and 5.8.x -- I take requests (README).
    ** The third rule of perl club is a statement of fact: pod is sexy.

      I tried your program and it works fine (I use Solaris), I guess the problem lies in the fact that my perl script is called from another perl script.

      So if we add the following test code:
      #######
      # calling.pl

      eval { system ("test.pl"); };
      $exit_val = $? >> 8;

      to call your previous test code. If I then run calling.pl and use ctrl-c, I get returned value as 0.

      Mags
      Here is the full code I used (I have tried also the fork-exec method) but no luck:

      ### Calling.pl
      #!/usr/local/bin/perl -w

      #eval { system ("./called.pl"); };
      #$exit_value = $?;

      #$exit_value = system ("./called.pl");

      if ($pid2 = fork) {
      # parent catches INT
      print "IN PAR\n";
      local $SIG{INT} = sub { print "In parent ...wait\n" };
      waitpid ($pid2, 0);
      }
      else {
      die "cannot fork: $!" unless defined $pid2;
      eval { exec ("./called.pl"); };
      }

      print "\nE-at = $@\n";
      print "\nE-! = $!\n";

      print "\nE = $exit_value\n";

      $exit_value = $exit_value >> 8; # Get the higher byte which has the real exit value
      print "\nE1 = $exit_value\n";


      ### called.pl
      #!/usr/local/bin/perl -w

      if (@ARGV) {
      $SIG{INT} = \&exit_gracefully;
      for(1..10){
      warn "called sleeping $_";
      select undef, undef, undef, 0.5;
      }
      exit 1;
      } else {
      warn "calling system\n";
      system ( $^X, __FILE__ , 'called');

      $exit_val = $? >> 8;

      warn "\n exit_val $exit_val";
      }

      sub exit_gracefully
      {
      $SIG{INT} = \&exit_gracefully;
      print "@ARGV Program interrupted .. \n";
      exit (3);
      }

      ###Output.txt

      IN PAR
      calling system
      called sleeping 1 at ./called.pl line 6.
      called sleeping 2 at ./called.pl line 6.
      called sleeping 3 at ./called.pl line 6.
      called sleeping 4 at ./called.pl line 6.
      ^Ccalled Program interrupted ..
      In parent ...wait

      exit_val 3 at ./called.pl line 16.

      E-at =

      E-! = Interrupted system call
      Use of uninitialized value in concatenation (.) or string at ./calling.pl line 22.

      E =

      Use of uninitialized value in right bitshift (>>) at ./calling.pl line 24.

      E1 = 0
Re: exit value not passed back
by muntfish (Chaplain) on Oct 06, 2004 at 08:33 UTC

    I suspect the exit value is unsigned, so your negative return code is causing a problem here. perldoc -f exit suggests that:

    The only universally recognized values for EXPR are 0 for success and 1 for error; other values are subject to interpretation depending on the environment in which the Perl program is running.

    Try it with some positive values and see what you get.


    s^^unp(;75N=&9I<V@`ack(u,^;s|\(.+\`|"$`$'\"$&\"\)"|ee;/m.+h/&&print$&
      Well I tried exit value of 3, but still getting $? returned as 256 and when I shift it right by 8 bits I still get 1 !!!

      Mags

        That is odd. I used your code as the basis of a test program and got results as expected, after the system() returns, $? = 768, shift it right 8 bits and you get 3 (which is what I had called.pl exit with).

        This is on Unix (HP-UX) by the way. Things may vary on other platforms - I think that is what the perldoc extract I quoted before is trying to say. What OS are you using?


        s^^unp(;75N=&9I<V@`ack(u,^;s|\(.+\`|"$`$'\"$&\"\)"|ee;/m.+h/&&print$&