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

Hi guys, I'm coding a perl script.
I should catch the "exit code" (like $?) of the process.

I'm using IPC::Open3 because I need read the "stdout"
and "stderr" in real-time when the execution is performed.

My trouble is I can't found anyway to catch the "exit code" from "test.pl".
How can I do it?

Thanks in advance for your help.
Fede

The script like something like this:
--- snip snip --- #!/usr/local/bin/perl use strict; use warnings; use IO::Handle; use IO::Select; use IPC::Open3; use POSIX ":sys_wait_h"; ++$|; # force flush #+-------------------------------------------------------------------- +---+# # Sub: spawn_proc # Spawn process # Input: (null) # Return: (null) #+-------------------------------------------------------------------- +---+# sub spawn_proc { my $cmd = "./test.pl"; local $SIG{PIPE} = sub { die "pipe broke" }; my $ref_rfh = \*RDRFH; my $ref_efh = \*ERRFH; my $pid = open3(\*WTRFH, \*RDRFH, \*ERRFH, $cmd); my $sel = IO::Select->new(); $ref_rfh->autoflush(1); $ref_efh->autoflush(1); $sel->add($ref_rfh, $ref_efh); print "Executing: $cmd\n"; while( my @ready = $sel->can_read ) { foreach my $fh (@ready) { my $line = $fh->getline; if($fh->fileno == $ref_rfh->fileno) { print "stdout: $line" if($line); } elsif ($fh->fileno == $ref_efh->fileno) { print "stderr: $line" if($line); } $sel->remove($fh) if(eof($fh)); } } close (RDRFH) || die("1 Return: $? | $@ | $!\n"); close (ERRFH) || die("2 Return: $? | $@ | $!\n"); close (WTRFH) || die("3 Return: $? | $@ | $!\n"); print "Done.\n"; } spawn_proc(); exit(0); --- snip snip ---

Edit by castaway - fixed mixed code/pre tags

Replies are listed 'Best First'.
Re: Catching "exit code" from IPC::Open3
by BrowserUk (Patriarch) on Jun 22, 2004 at 22:06 UTC

    From IPC::Open3 pod

    open3() does not wait for and reap the child process after it exits. Except for short programs where it's acceptable to let the operating system take care of this, you need to do this yourself. This is normally as simple as calling waitpid $pid, 0 when you're done with the process.

    From perlfunc:waitpid

    Waits for a particular child process to terminate and returns the pid of the deceased process, ... The status is returned in $?.

    So,I think the answer is that you need to call waitpid with the $pid returned by open3() and then inspect $? to retrieive the exit status.


    Examine what is said, not who speaks.
    "Efficiency is intelligent laziness." -David Dunham
    "Think for yourself!" - Abigail
    "Memory, processor, disk in that order on the hardware side. Algorithm, algoritm, algorithm on the code side." - tachyon
      What do you think about this?
      
      
      ... ... my $getpid = -1; while ( my @ready = $sel->can_read ) { ... ... # If end-of-file (STDERR or STDOUT) if ( eof ($fh) ) { # Get pid my $getpid = waitpid($pid, WNOHANG); $retcode = $? / 256 if ( $getpid == $pid ); } } print "Exit code: $retcode\n"; ... ...
      Thanks again, Fede

        I think that there is no need to do this conditionally inside the while loop. You could just as well do it after the while loop terminates.

        However, I am not sure that your while loop is constructed correctly. What happens if

        1. The external process produces some of its output, then gets swapped out.
        2. Your while loop runs, finds some input and processes it & loops back.
        3. The external process has not yet had a timeslice, so it hasn't had the opportunity to produce the rest of it's output.
        4. The while loop tests can_read(), finds nothing available, so the loop terminates.

        I've never had occasion to use IO::Select, so I have no idea if this is a realistic scenario. It's not clear to me whether can_read() means "The connection is still open so if you attempt to read you might get something" or "some data has been received, so if you read you will get something".

        Maybe you already know that you while loop is ok as is.

        The basic scheme of extracting the exit code from $? after calling waitpid seems correct to me.


        Examine what is said, not who speaks.
        "Efficiency is intelligent laziness." -David Dunham
        "Think for yourself!" - Abigail
        "Memory, processor, disk in that order on the hardware side. Algorithm, algoritm, algorithm on the code side." - tachyon
Re: Catching "exit code" from IPC::Open3
by etcshadow (Priest) on Jun 22, 2004 at 21:19 UTC
    You may find things a lot easier by using IPC::Run instead of rolling your own with IPC::Open3. First of all, it'll be easier than worrying about duplicating all of that hard work, and second of all, you can easily access the exit codes.
    ------------ :Wq Not an editor command: Wq
      I prefer avoid use IPC::Run.
      Thanks you anyway,
      Fede