背景
当你使用system(LIST) where LIST
如果有多个元素,Perl 不会调用 shell,而是直接调用第一个元素给出的程序LIST
,并使用列表的其余部分作为要传递的命令行参数verbatim, with no由 shell 进行插值,包括no根据空格分割参数。
所以在你的第一个例子中,Perl 正在运行命令bash
并传递字符串"$easyrsa_path/easyrsa build-client-full $clientname nopass"
,字面意思是one很长的参数,在你的第二个例子中,它正在运行命令bash
并传递两个参数$easyrsa_path
and "build-client-full $clientname nopass"
。但是,我假设easyrsa
需要将三个参数作为其参数列表中的单独字符串,shell 通常会将其拆分,但由于您的两次调用system
没有使用 shell,它不起作用。
system (and exec)根据文档有四种解释其参数的方法:
如果您传递单个字符串(包括LIST
只有一个元素)不包含任何 shell 元字符,它被分割成单词并直接传递给execvp(3)(意味着它绕过了外壳)。Warning:此调用很容易与以下内容混淆 - 单个元字符将导致调用 shell,这可能很危险,尤其是在将未经检查的变量插入命令字符串时。
-
如果您传递单个字符串(包括LIST
(只有一个元素)确实包含 shell 元字符,整个参数将传递到系统的命令 shell 进行解析。通常情况下,那就是/bin/sh -c
在 Unix 平台上,但是“默认 shell”的想法是有问题的,并且当然不能保证它会是bash
(虽然它could be).
Warning:在这个调用中system
,您拥有 shell 的全部功能,这也意味着您有责任正确引用和转义任何 shell 元字符和/或空格。我推荐你only如果您使用此表格明确想要shell 的能力,否则,通常最好使用以下两者之一。
如果有多个参数LIST
,这称为execvp(3)
与参数LIST
,意味着避免使用 shell。
(有关 Windows 上的注意事项,请参阅下文。)
表格system {EXPR} LIST
always运行名为的程序EXPR
并避开外壳,无论里面有什么LIST
。
(有关 Windows 上的注意事项,请参阅下文。)
如果您想传递 shell 通常会解释的特殊字符,则后两者是可取的,而且我实际上总是建议这样做,因为盲目地将用户输入传递到system
可以打开一个安全漏洞 - 我写了一篇更长的文章关于 PerlMonks.
解决方案
@Borodin 和 @AnFi 已经指出:如果你简单地将LIST
正确地,它应该可以工作 - 看起来你不需要任何功能bash
或这里的任何外壳。并且不要忘记检查错误!
system("$easyrsa_path/easyrsa","build-client-full",$clientname,"nopass") == 0
or warn "system failed: \$? = $?";
请注意,有一些很好的模块提供了的替代品system and qx,我的首选模块通常是IPC::Run3。如果您想捕获外部命令的输出,这些模块非常有用。在这种情况下,IPC::System::Simple可能会更容易,因为它提供了一个直接替代品system
具有更好的错误处理能力,以及systemx
它总是避开外壳。 (该模块是什么autodie当你说时使用use autodie ':all';
.)
use IPC::System::Simple qw/systemx/;
systemx("$easyrsa_path/easyrsa","build-client-full",$clientname,"nopass");
请注意,如果您really想打电话bash
,你需要添加-c
选项并说system("bash","-c","--","$easyrsa_path/easyrsa build-client-full $clientname nopass")
。但正如我上面所说,我强烈建议不要这样做,因为如果$easyrsa_path
or $clientname
包含任何 shell 元字符或恶意内容,您最终可能会遇到一个大问题。
Windows
Windows 比上面的更复杂。该文档说,避免调用 shell 的唯一“可靠”方法是system PROGRAM LIST
形式,但在 Windows 上,命令行参数不是作为列表传递,而是作为单个大字符串传递,并且由被调用的命令而不是 shell 来解释该字符串,并且不同的命令可能会以不同的方式执行此操作 -see also。 (我听说过一些好消息Win32::ShellQuote, 尽管。)
另外,还有一个特别的system(1, @args)
表格记录在perlport.