我需要eval
Perl中的某些代码,有时可能会在其中包含exit()
调用。一个非常简单的例子是:
use strict;
use warnings;
eval "some_function()";
die $@ if $@;
print "Still alive!\n";
sub some_function {
print "Hello from some_function\n";
exit;
}
我永远不会“活着!”因为exit()
来电。
我尝试在%SIG
(QUIT,STOP,TERM,BREAK等)中设置一些键,但这不起作用。我还尝试重新定义CORE::exit
但没有成功。
exit()
如何阻止eval
来电有效?
答案 0 :(得分:8)
您可以覆盖exit
,但必须在编译时执行此操作。因此,使用一个标志来表示覆盖是否有效。
our $override_exit = 0;
BEGIN {
*CORE::GLOBAL::exit = sub (;$) {
die "EXIT_OVERRIDE\n" if $override_exit;
CORE::exit($_[0] // 0);
};
}
eval {
local $override_exit = 1;
some_function();
};
die "Exit was called\n" if $@ eq "EXIT_OVERRIDE\n";
die $@ if $@:
但这会产生一个可能无意中发现的异常。所以我们改用last
。
our $override_exit = 0;
BEGIN {
*CORE::GLOBAL::exit = sub (;$) {
no warnings 'exiting';
last EXIT_OVERRIDE if $override_exit;
CORE::exit($_[0] // 0);
};
}
my $exit_was_called = 1;
EXIT_OVERRIDE: {
local $override_exit = 1;
eval { some_function() };
$exit_was_called = 0;
die $@ if $@;
}
die "Exit was called\n" if $exit_was_called;
请注意,eval BLOCK
用于捕获异常。 eval EXPR
用于编译代码。
答案 1 :(得分:3)
exit
并不意味着被困,所以eval
不是解决方案。您可以将剩余的代码放在END
块中运行:
some_function();
END { print "Still alive! For now...\n"; }
sub some_function {
print "Hello from some_function\n";
exit;
}
但如果你绝对需要阻止exit
杀死脚本,那么你必须在编译时重新定义exit()
:
BEGIN { *CORE::GLOBAL::exit = sub (;$) { } } # Make exit() do nothing
some_function();
print "Still alive!\n"; # Gets printed
*CORE::GLOBAL::exit = *CORE::exit; # Restore exit()
exit;
print "I'm dead here.\n"; # Doesn't get printed
sub some_function { exit }
如果您对更强大的解决方案感兴趣,可以使用CPAN中的Test :: Trap模块为您封装这一点丑陋。我个人会在本地修补exit
ing some_function()
以使用croak
,如果它是一个模块,可能会在补丁中提交错误报告。
如果您只是eval
用户输入,并且您不希望他们能够拨打exit
,请确认该字符串不包含对{{1}的调用或者是一个间接退出的子程序,然后是exit
它。就个人而言,如果用户输入要评估的任意代码,我会比eval
和unlink
更害怕fork
。