2012-07-26 132 views
5

我使用的是Perl的Safe模块中的reval,我想阻止它在生成警告时无法解析被评估的字符串(实际上,我想阻止它生成任何警告) 。“没有警告;”在安全隔间

例如,下面的代码:在

use strict; use warnings; 
use Safe;  
use feature qw/say/; 
my $cft = Safe->new; 

my $x = $cft->reval(') 1'); 
my $y = $cft->reval('2' ); 
say "x: $x"; 
say "y: $y"; 

结果:

Number found where operator expected at (eval 5) line 1, near ") 1" 
    (Missing operator before 1?) 
Use of uninitialized value $x in concatenation (.) or string at ./test line 12. 
x: 
y: 2 

我试图做到的,是有$ X =民主基金和$ Y = 2,且无警告。 我试图提出“没有警告;”一个新的范围内,但它从重估中产生的警告没有效果(虽然,正如@DavidO指出的那样,沉默的“初始化值”警告):

use strict; use warnings; 
use Safe;  
use feature qw/say/; 
my $cft = Safe->new; 
{ 
    no warnings; 
    my $x = $cft->reval(') 1'); 
    my $y = $cft->reval('2' ); 
    say "x: $x"; 
    say "y: $y"; 
} 

我想,不知何故'没有警告'必须放在安全隔间内,所以我也试图在“无警告”之前加上警告。琴弦被eval'ed:

use strict; use warnings; 
use Safe; 
use feature qw/say/; 
my $cft = Safe->new; 
{ 
    my $x = $cft->reval('no warnings;' . ') 1'); 
    my $y = $cft->reval('no warnings;' . '2' ); 
    say "x: $x"; 
    say "y: $y"; 
} 

这样重估不发出任何警告,但两个变量都是民主基金:

Use of uninitialized value $x in concatenation (.) or string at ./test line 10. 
x: 
Use of uninitialized value $y in concatenation (.) or string at ./test line 11. 
y: 

我不知道什么尝试,我希望问题描述足够清楚。

+1

您的第二次尝试实际上不会产生与第一次相同的输出。它仍然会产生“编译时”错误(实际上是reval编译时错误),但不会产生与在'say'语句中插入未初始化值有关的运行时警告。所以你已经在上面的第二个片段中解决了你的一半问题(压制了警告)。另一半(压制编译时错误)更成问题。 – DavidO 2012-07-26 21:20:46

+0

是的,你说得对。我甚至没有注意到,因为我在这里主要关心的是重新评估 - 未初始化的变量警告是我试图保持示例简短的结果。无论如何,我已更新了该帖子以使其更清晰。谢谢! – andrefs 2012-07-26 21:33:01

回答

4

如果您检查[email protected],您会看到$cft->reval('no warnings;' . ') 1');失败。 'require' trapped by operation mask at (eval 5) line 1.。换句话说,Safe正在做它的工作,并防止代码尝试加载库。

$cft->reval('BEGIN { warnings->unimport; }) 1');会工作,假设警告已经加载到隔间外。但是,这不会消除编译时错误。不像evalreval似乎让他们通过。使用amon的STDERR静音技术。

+0

双层方法效果最佳。该警告正在'reval'之外产生,并且可以在更广的范围内被压制。编译时错误在'reval'内部产生,并且非常固执。这是重定向STDERR是最不好的选择,imho。 (另一种选择是明确允许安全隔间内的'eval',但为什么还要使用Save?:))。 – DavidO 2012-07-26 21:27:12

+0

虽然很有趣,在安全隔间内执行一个'qr/[c-a] /''',这是一个无效的正则表达式,它会在编译过程中抛出一个错误,它会被reval成功捕获。 – DavidO 2012-07-26 21:30:29

+0

感谢您的回复。 @阿蒙的方法似乎是沉默最严重的解析错误的最佳选择。 BEGIN {warnings-> unimport;}似乎可以工作,除非您在被撤销的字符串中显式调用类似警告“foo”的内容:P – andrefs 2012-07-26 21:46:26

4

no warnings禁止所有警告use warnings编译指示生成。您可能也想要删除任何strict。但严重的解析错误会以任何方式弹出。

如果你想无论多么病态执行任何代码,没有任何输出到STDERR,您应在本地修改信号处理程序:

{ 
    # I know what I'm doing! 
    local $SIG{__WARN__} = sub {}; # locally ignore any warnings 
    eval $code; # catches all "die" 
} 

,或者我们可以重新STDERR/dev/null

{ 
    # I know what I'm doing! 
    open my $oldSTDERR, '>&' \*STDERR or die; 
    close STDERR or die; 
    open STDERR, '>', '/dev/null' or die; 

    eval $code; 

    close STDERR or die; 
    open STDERR, '>&', $oldSTDERR or die; 
    close $oldSTDERR; 
} 
+1

但是'eval $ code'不允许在安全隔间内。我认为设置'$ SIG {}'处理程序也是被禁止的(并且是有原因的)。在'reval'之外建立'$ SIG {}'处理程序也不会有效。我认为重定向STDERR可能是编译reval代码时产生的错误的最干净的kludge。该警告可以通过正常手段进行压制,因为它发生在reval之外。 – DavidO 2012-07-26 21:25:06

+0

@amon提出的第一种解决方案是使用以下代码: use strict;使用警告; 使用安全; 使用功能qw/say /; my $ cft = Safe-> new; { local $ SIG {__ WARN__} = sub {}; my $ x = $ cft-> reval(')1'); my $ y = $ cft-> reval('2'); 说“x:$ x”; 说“y:$ y”; } 这似乎正是我所期待的,谢谢! – andrefs 2012-07-26 21:38:25

+0

@andrefs如果此答案适合您,请“接受”此答案,将您的问题标记为“已关闭”。 – amon 2012-07-26 21:48:36