2012-03-22 37 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的命令。

相关问题