为什么Perl';s IO::管道异常的行为与评估块中的croak或die不同?
我在程序中注意到,从IO::Pipe引发的异常行为异常,我无法理解它在做什么(更不用说它是如何做的)。我将其归结为一个简单的示例程序:为什么Perl';s IO::管道异常的行为与评估块中的croak或die不同?,perl,exception-handling,eval,die,Perl,Exception Handling,Eval,Die,我在程序中注意到,从IO::Pipe引发的异常行为异常,我无法理解它在做什么(更不用说它是如何做的)。我将其归结为一个简单的示例程序: use strict; use warnings; use Carp; use IO::Pipe; my($path) = shift; my($bad) = shift || ""; eval { if ($path =~ m{pipe}i) { my($bin) = ($bad ? "/bin/lsddd" : "/bin/ls
use strict;
use warnings;
use Carp;
use IO::Pipe;
my($path) = shift;
my($bad) = shift || "";
eval {
if ($path =~ m{pipe}i) {
my($bin) = ($bad ? "/bin/lsddd" : "/bin/ls");
my($pipe) = IO::Pipe->new();
$pipe->reader("$bin -l .");
print "$_" while <$pipe>;
$pipe->close;
}
elsif ($path =~ m{croak}i) {
croak "CROAKED" if $bad;
}
else {
die "DIED" if $bad;
}
};
if ($@) {
my($msg) = $@;
die "Caught Exception: $msg\n";
}
die "Uh-oh\n" if $bad;
print "Made it!\n";
及
但是,当我沿IO::Pipe路径发送错误时,它会报告错误,但程序将继续执行,直到到达外部die
:
$ perl example.pl pipe foo
Caught Exception: IO::Pipe: Cannot exec: No such file or directory at example.pl line 15.
Uh-oh
第一个问题是为什么——为什么程序报告“捕获的异常”消息而不终止?第二个问题是如何防止这种情况发生?如果程序无法运行,我希望程序停止执行。在感兴趣的情况下,有两个进程在eval
之后运行。您可以通过在if($@)
之前添加print语句来看到这一点。一个通过eval
进入最后一个die
读取器
在与参数一起使用时分叉,以打开进程。当父进程返回时,该进程在子进程中执行,并带有其pid。此代码在中
当此操作失败时,子croak
s会显示您收到的消息。但是父级返回,因为它与子级没有IPC,而子级将通过exec
消失。因此,父对象逃逸并沿着eval
向下移动。该进程没有$@
,如果($@),则绕过
在使用reader
打开进程的情况下,这似乎是错误处理中的一个漏洞
有办法解决这个问题。$pipe
是一个错误,如果它不好,我们可以检查它并退出额外的进程(但是简单的$pipe->error
在这两种情况下都是相同的)。或者,由于涉及到,我们可以转到$?
,当发生错误时,它实际上是非零的
# ...
$pipe->close;
exit if $? != 0;
(或者更确切地说,先检查一下)。这仍然是一个“修复”,可能并不总是有效。其他探测$pipe
或查找逃犯PID的方法有点模糊(或者更糟的是,深入挖掘类内部)
另一方面,从程序中收集输出和退出代码的简单方法是使用模块。一个好的选择是。还有其他的,像和,或核心,但相当低的水平
经过澄清,正常的打开也应该足够了。作为旁白,我使用IO::Pipe是因为我想收集正在运行的程序的输出及其退出代码,如果命令无法运行,我想生成一个异常;如果有更好的方法,尤其是不存在上述问题的方法,请在这里的评论中告诉我。从简单到强大,有很好的模块用于收集输出和退出代码。一旦你有了退出密码,你就可以询问它并做你想做的事,当然你可以扔一个die
。如果我正确理解了目的——运行一个程序并获取其输出,然后选中exit——我不明白为什么要使用IO::Pipe
。如果只需要读取或写入外部进程,而不需要同时读取或写入外部进程,则使用;或或(比IPC::Open3更好的接口,但不在core中),如果您需要同时读取和写入进程。如果您只是从管道中读取,则IPC::Open3确实可以,并且它会根据需要将启动子程序的错误传播到父程序中的异常中。(我自己将这一功能添加到open3中。)
$ perl example.pl pipe foo
Caught Exception: IO::Pipe: Cannot exec: No such file or directory at example.pl line 15.
Uh-oh
# ...
$pipe->close;
exit if $? != 0;