我正在编写一个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
任何人都能看到我做错了什么?
感谢。
答案 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(bash
或sh
)来强制解析变量。
如果您所做的只是测试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命令的另一个字符串参数。