Beefy Boxes and Bandwidth Generously Provided by pair Networks
Just another Perl shrine
 
PerlMonks  

delayed die and open3

by Random_Walk (Prior)
on Mar 31, 2005 at 14:56 UTC ( [id://443851]=perlquestion: print w/replies, xml ) Need Help??

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

Oh Brothers and Sisters in perl I beg the fruits of your wisdom.

I have a simple script I am using to get the hang of IPC::open3. When I do the open I wrap it in an eval and die if it failed. The die however does not happen until after the rest of the script is done.

#!/usr/bin/perl use strict; use warnings; use IPC::Open3; my($in, $out, $err, $pid); open( $out, ">&STDOUT" ) or die "Can't dup STDOUT to OUTPUT: $!\n"; open( $err, ">&STDERR" ) or die "Can't dup STDERR to OUTERR: $!\n"; eval { $pid = open3($in, $out, $err, @ARGV) }; die "open3 gave trouble: $@\n" if $@; print "It is running\n"; close $in; print "stdout:\n"; print while <$out>; close $out; print "stderr:\n"; print while <$err>; close $err; __END__ # this is expected ./open3 echo "Hello World" It is running stdout: Hello World stderr: # this is confusing the proverbial out of me ./open3 nosuchcommand It is running stdout: stderr: open3 gave trouble: open3: exec of nosuchcommand failed at ./open3 lin +e 15 # The die obviosly ran but the code did not die, # ran to completion regardless then printed the error

Cheers,
R.

Pereant, qui ante nos nostra dixerunt!

Replies are listed 'Best First'.
Re: delayed die and open3
by tlm (Prior) on Mar 31, 2005 at 15:31 UTC

    The parent is printing, the child is dying. Try this:

    use strict; use warnings; use IPC::Open3; $|=1; print "parent pid: $$\n"; my($in, $out, $err, $pid); # duplicate stderr and stdout open( $out, ">&STDOUT" ) or die "Can't dup STDOUT to OUTPUT: $!\n"; open( $err, ">&STDERR" ) or die "Can't dup STDERR to OUTERR: $!\n"; eval { $pid = open3($in, $out, $err, @ARGV) }; die "$$ open3 gave trouble: $@\n" if $@; print "$$ It is running\n"; close $in; print "stdout:\n"; print while <$out>; close $out; print "$$ stderr:\n"; print "$$ $_" while <$err>; close $err;

    the lowliest monk

      An excellent example that makes it pretty clear what is going on, thanks. I am still puzzled though, the die runs in the child but how did the die get in there ? Is open3 forking and if so how does it decide to run the die but not the following print which comes only from the parent. Is there any way in the parent to trap failure of the child ?

      # here the die runs in the child: nph>perl -MIPC::Open3 -le'print "dad: $$";eval {$pid = open3(*IN, *OUT +, *ERR, @ARGV);}; die "$$ ACK $@\n" if ($@);print <ERR>' nosuch dad: 62718 55596 ACK open3: exec of nosuch failed at -e line 1 # yet here in the same code it runs in the parent !!! nph>perl -MIPC::Open3 -le'print "dad: $$";eval {$pid = open3(*IN, *OUT +, *ERR, @ARGV);}; die "$$ ACK $@\n" if ($@);print <ERR>' dad: 25600 25600 ACK open3(*main::IN, *main::OUT, *main::ERR): not enough argumen +ts at -e line 1 # and if I remove the print <ERR> I alter the behaviour again nph>perl -MIPC::Open3 -le'print "dad: $$";eval {$pid = open3(*IN, *OUT +, *ERR, @ARGV);}; die "$$ ACK $@\n" if ($@);print "moo" ' nosuch dad: 55592 moo nph>

      Thanks,
      R.

      Pereant, qui ante nos nostra dixerunt!

        OK, try this:

        use strict; use warnings; use IPC::Open3; $|=1; print "parent pid: $$\n"; my($in, $out, $err, $pid); # duplicate stderr and stdout open( $out, ">&STDOUT" ) or die "Can't dup STDOUT to OUTPUT: $!\n"; open( $err, ">&STDERR" ) or die "Can't dup STDERR to OUTERR: $!\n"; eval { $pid = open3($in, $out, $err, @ARGV) }; die "$$ open3 gave trouble: $@\n" if $@; print "$$ It is running\n"; close $in; print "$$ stderr:\n"; print "[ $$ $_ ]" while <$err>; close $err; __END__
        You'll see that the child's error message is being printed by the parent. Now replace the die with warn. You'll see that if the open3 call fails, the child goes on and tries to execute the parent's code. In other words, if the open3 call succeeds, you have a successful fork+exec: the child is off on its merry way executing your pipe. When you give the program a bogus argument like 'nosuch', the fork succeeds (hence no $@), but the exec fails. The IPC::Open3 docs talk about exec failures; to trap them you need to handle the SIGPIPE yourself.

        the lowliest monk

        I was asking this same question myself.

        Take out your "die" and it becomes evident what happens

        The fork inside open3 (and yes, it does fork) forks the PROCESS. The whole thing. So your parent continues to run as normal, and, as the docs for IPC::open3 say, it does NOT wait for the child to run.

        Therefore, the child keeps running after the parent is finished, dies and hits the die in your main program (because it forks the entire process).
        --------------
        "But what of all those sweet words you spoke in private?"
        "Oh that's just what we call pillow talk, baby, that's all."
Re: delayed die and open3
by cazz (Pilgrim) on Mar 31, 2005 at 15:31 UTC
    eval is not trapping the failed open3 call as you expect. Trim your code down to this:
    [bmc@hacked lib]$ perl -MIPC::Open3 -e 'eval {$pid = open3(*IN, *OUT, +*ERR, @ARGV);}; print "ACK $@\n" if ($@);' asdf [bmc@hacked lib]$
    Note that ack isn't printed. eval is working as expected as you can see when you call the same code with no args:
    [bmc@hacked lib]$ perl -MIPC::Open3 -e 'eval {$pid = open3(*IN, *OUT, +*ERR, @ARGV);}; print "ACK $@\n" if ($@);' ACK open3(*main::IN, *main::OUT, *main::ERR): not enough arguments at +-e line 1 [bmc@hacked lib]$

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://443851]
Approved by moot
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others learning in the Monastery: (5)
As of 2024-04-19 02:07 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found