2012-07-26 137 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