运行perl -e'使用[module]'的Bash / shell错误:在-e第1行的EOF之前的任何地方都找不到字符串终止符“'”

时间:2012-03-22 14:05:27

标签: perl bash shell

我正在编写一个shell脚本,在运行之前需要检查系统Perl更新是否已经破坏了粘贴在一起的Perl脚本。我不断得到解析错误。要在命令行上重现:

$ 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

任何人都能看到我做错了什么?

感谢。

4 个答案:

答案 0 :(得分: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强制shell重新解析该行,没有错误。

小心;简单地使用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
$

答案 1 :(得分:1)

我不确定shell正在做什么,但将管道$check加入sh似乎有效:

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

然而,使用像Module::Load::Conditional之类的东西来做这件事要少得多。您也可以使用pminst

答案 2 :(得分:1)

基本上,如果将命令放在变量中,shell只会解析一次该行(即当它消耗变量时),因此当命令本身包含shell特殊字符时,它将不会处理它。在你的情况下,shell的东西是'2>&1。这就是为什么bash会给你错误的原因。即使您使用'删除-m$module,您仍会收到有关2>&1

的错误消息

正如上面的答案所说,你需要使用eval或调用子shell(bashsh)来强制解析变量。

如果您所做的只是测试perl将编译所需的模块,这还不错吗?

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

如果一切都很酷,那么ok将为0,如果出现某种错误,则为{0}。如果您真正的问题比发布的示例复杂得多,则可能不合适。

答案 3 :(得分:0)

在bash中执行此操作的唯一安全方法是使用数组。这将使用空格正确维护参数。

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

请注意,stderr / stdout重定向不能是命令数组的一部分,您必须将其指定为命令的一部分,否则它只是perl命令的另一个字符串参数。