2012-03-22 17 views
3

我在寫一個shell腳本,運行需要檢查系統之前, Perl更新並未破壞Perl腳本被粘在一起。我不斷收到看起來像一個解析錯誤。要在命令行上重現此操作,請執行以下操作:猛砸/殼錯誤運行的perl -e「使用[模塊]」:無法找到字符串結束「'」在-e行EOF之前的任何地方1

$ module='Scalar::Util'; check="perl -e 'use $module' 2>&1"; check_status=`$check`; echo $check 
Can't find string terminator "'" anywhere before EOF at -e line 1. 
perl -e 'use Scalar::Util' 2>&1 

任何人都看到我在做什麼錯了?

謝謝。

回答

9

處理的論點與他們的空間一樣,充其量是棘手的;儘量避免這樣做。

您還應該使用更多的垂直空間; 「單行條款」是一個貶義詞,而不是批准條款。

您有:

module='Scalar::Util' 
check="perl -e 'use $module' 2>&1" 
check_status=`$check` 
echo $check 

麻煩的是,當shell進程:

`$check` 

它分裂,在字的邊界線,產生爭論:

perl 
-e 
'use 
Scalar::Util' 
2>&1 

注意I/O重定向被視爲一個參數!爲了避免這個問題,在這種情況下,你可以使用:

module='Scalar::Util' 
check="perl -e 'use $module' 2>&1" 
check_status=`eval $check` 
echo $check 

eval迫使外殼重新分析了線,沒有得到任何錯誤。

要小心;僅僅使用eval並不總是解決這些問題的方法。特別是,如果你有反斜槓,美元或反引號周圍(或以上引號),然後eval可以簡單的化合物中的問題。檢查Perl中是否存在一個模塊的

一種方法是:

perl -M$module -e "print $module::VERSION . '\n'" 

,使該模塊的版本號(和複雜的字符串)。你也可以簡單地做:

perl -M$module -e exit 

如果模塊被加載,這將與狀態0退出,如果不是噴涌向前的錯誤等。

$ perl -MSalar::Util -e exit 
Can't locate Salar/Util.pm in @INC (@INC contains: /Users/jleffler/Perl/v5.14.1-64/lib/perl5/site_perl/5.14.1/darwin-2level /Users/jleffler/Perl/v5.14.1-64/lib/perl5/site_perl/5.14.1 /Users/jleffler/Perl/v5.14.1-64/lib/perl5/5.14.1/darwin-2level /Users/jleffler/Perl/v5.14.1-64/lib/perl5/5.14.1 .). 
BEGIN failed--compilation aborted. 
$ echo $? 
2 
$ 
+0

完美。奇蹟般有效。謝謝!我同意你關於單線的觀點。在我的腳本中,代碼是垂直間隔的,但是在shell中,我將它打包成一行,所以我可以使用向上箭頭進行大量重複試驗。我應該使用單獨的行來使問題示例中的可讀性更高。 – David 2012-03-22 14:32:59

+0

請不要暗示人們使用eval--如果不小心使用,這是一種生成安全漏洞的簡單方法。 Bash有數組:'check =(perl -e「使用$ module」)',可引用爲'「{{check [@]}」'(引號很重要,順便說一句)......但爲什麼它會是希望將命令封裝在數組中_或_字符串而不是shell函數我很不清楚。 – 2012-03-22 14:49:33

+0

btw,'perl -M $ module -e exit'可以簡化爲'perl -M $ module -e1'。 – ikegami 2012-03-22 17:59:55

1

我不知道什麼殼做的,但管道$checksh似乎工作:

module='Scalar::Util'; check="perl -e 'use $module' 2>&1";echo $check |sh 

但是,它的影響則要小得多笨重使用類似Module::Load::Conditional做到這一點。您也可以使用pminst

+1

我接受喬納森·萊弗勒的答案僅僅是因爲我第一次讀到它,它解釋到底是什麼殼在做我的命令字符串,但我給你的迴應+1,因爲我不知道模塊::負載並::條件和pminst,他們看起來很有用。非常感謝。 – David 2012-03-22 14:37:17

+0

順便說一句,我會考慮Module :: Load :: Conditional,因爲我可以定製check_status輸出。 – David 2012-03-22 14:41:58

1

基本上,如果你把命令的變量,shell只解析線一次(即當消費變量),當命令本身包含shell特殊字符,所以不會處理它。在你的情況下,shell的東西是'2>&1。這就是bash給你錯誤的原因。即使你使用-m$module刪除'是你仍然會得到有關2>&1

錯誤,以便爲上述回答說,你需要使用eval或調用子殼(bashsh)來強制變量是解析。

如果你正在做的是測試一個Perl的將編譯所需要的模塊,這是不夠好?

module='Scalar::Util' 
perl -m$module 
ok=$? 

這裏ok0如果一切都很酷,或非0,如果有某種錯誤。如果您真正的問題比發佈的示例複雜得多,可能不太合適。

+0

感謝您解釋一次性解析問題。我曾考慮過使用$?但我不確定perl的返回碼,並且懶得通讀整個perlrun手冊頁,我也想捕獲錯誤文本。順便說一句,我試過你的例子,但是控制檯掛在'perl -m $模塊'上。也許你的意思是這樣的:perl -m $ module -e'print'?這似乎是你想要的。 +1的有用信息。 – David 2012-03-22 14:49:13

0

比較安全的方法在bash做,這是使用數組。這將適當地保持與空白的參數。

module='Scalar::Util' 
check=(perl -e "use $module") 
check_status=$("${check[@]}" 2&>1) # must use quotes here 
status=$? 
echo "$status: $check" 

注意標準錯誤/標準輸出重定向不能命令陣列的一部分,你必須將其指定爲命令的一部分,否則它只是一個字符串參數perl的命令。

相關問題