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!
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;
| [reply] [d/l] |
|
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!
| [reply] [d/l] |
|
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.
| [reply] [d/l] [select] |
|
| [reply] |
|
|
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]$
| [reply] [d/l] [select] |
|
|