为什么 Perl 的 IO::Pipe 异常的行为与 eval 块中的 croak 或 die 不同?
Why does Perl's IO::Pipe exception behave differently than croak or die in eval block?
我注意到在我的程序中,从 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");
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";
示例程序有两个参数,一个指示在 eval
块中执行哪个代码路径,第二个指示是否生成错误(任何计算结果为 false 的都不会产生错误)。当没有请求错误时,所有三个路径都按预期运行;他们都打印 Made it!
而没有错误消息。
当通过 croak
或 die
路径询问错误并 运行ning 时,它的行为也如我所料:异常被捕获、报告,程序终止.
$ perl example.pl die foo
Caught Exception: DIED at example.pl line 23.
和
$ perl example.pl croak foo
Caught Exception: CROAKED at example.pl line 11.
eval {...} called at example.pl line 10
当我在 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
第一个问题是 - 为什么程序报告 "Caught Exception" 消息但不终止?第二个问题是如何防止这种情况发生?如果程序不能 运行.
我希望程序停止执行
在感兴趣的eval
之后有两个过程运行。您可以通过在 if ($@)
之前添加打印语句来查看这一点。一个通过 eval
下降,从而到达最后一个 die
.
reader
与参数一起使用时会分叉,以打开进程。该进程在 child 中被 exec
编辑,而 parent returns 中带有其 pid。代码在 _doit
internal subroutine
当此操作失败时,child croak
会显示您收到的消息。但是 parent returns 无论如何,因为它与 child 没有 IPC,预计会通过 exec
消失。所以 parent 逃脱并沿着 eval
前进。该进程没有 $@
并绕过 if ($@)
.
这似乎是错误处理中的一个漏洞,在 reader
用于打开进程的情况下。
有很多方法可以解决这个问题。 $pipe
是一个 IO::Handle and we can check it and exit that extra process if it's bad (but simple $pipe->error
turns out to be the same in both cases). Or, since close 涉及,我们可以去 $?
这确实是 non-zero 当错误发生时
# ...
$pipe->close;
exit if $? != 0;
(或者更确切地说,首先检查它)。这仍然是一个 "fix,",可能并不总是有效。其他探测 $pipe
或查找逃逸者 PID 的方法有点晦涩(或者更糟的是,挖掘 class 内部结构)。
另一方面,从程序中收集输出和退出代码的一种简单方法是为此使用一个模块。一个不错的选择是 Capture::Tiny. There are others, like IPC::Run and IPC::Run3, or core but rather low-level IPC::Open3.
鉴于说明,正常的 open
也应该足够了。
我注意到在我的程序中,从 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");
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";
示例程序有两个参数,一个指示在 eval
块中执行哪个代码路径,第二个指示是否生成错误(任何计算结果为 false 的都不会产生错误)。当没有请求错误时,所有三个路径都按预期运行;他们都打印 Made it!
而没有错误消息。
当通过 croak
或 die
路径询问错误并 运行ning 时,它的行为也如我所料:异常被捕获、报告,程序终止.
$ perl example.pl die foo
Caught Exception: DIED at example.pl line 23.
和
$ perl example.pl croak foo
Caught Exception: CROAKED at example.pl line 11.
eval {...} called at example.pl line 10
当我在 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
第一个问题是 - 为什么程序报告 "Caught Exception" 消息但不终止?第二个问题是如何防止这种情况发生?如果程序不能 运行.
我希望程序停止执行在感兴趣的eval
之后有两个过程运行。您可以通过在 if ($@)
之前添加打印语句来查看这一点。一个通过 eval
下降,从而到达最后一个 die
.
reader
与参数一起使用时会分叉,以打开进程。该进程在 child 中被 exec
编辑,而 parent returns 中带有其 pid。代码在 _doit
internal subroutine
当此操作失败时,child croak
会显示您收到的消息。但是 parent returns 无论如何,因为它与 child 没有 IPC,预计会通过 exec
消失。所以 parent 逃脱并沿着 eval
前进。该进程没有 $@
并绕过 if ($@)
.
这似乎是错误处理中的一个漏洞,在 reader
用于打开进程的情况下。
有很多方法可以解决这个问题。 $pipe
是一个 IO::Handle and we can check it and exit that extra process if it's bad (but simple $pipe->error
turns out to be the same in both cases). Or, since close 涉及,我们可以去 $?
这确实是 non-zero 当错误发生时
# ...
$pipe->close;
exit if $? != 0;
(或者更确切地说,首先检查它)。这仍然是一个 "fix,",可能并不总是有效。其他探测 $pipe
或查找逃逸者 PID 的方法有点晦涩(或者更糟的是,挖掘 class 内部结构)。
另一方面,从程序中收集输出和退出代码的一种简单方法是为此使用一个模块。一个不错的选择是 Capture::Tiny. There are others, like IPC::Run and IPC::Run3, or core but rather low-level IPC::Open3.
鉴于说明,正常的 open
也应该足够了。