在Perl中使用system()调用时,是否必须转义shell args,还是自动完成?
参数将是用户输入,因此我想确保这不可利用.
如果您使用system $cmd, @args
而不是system "$cmd @args"
(数组而不是字符串),那么您不必转义参数,因为没有调用shell(请参阅系统). system {$cmd} $cmd, @args
即使$ cmd包含元字符并且@args为空(这也记录为exec的一部分),也不会调用shell .如果args来自用户输入(或其他不受信任的来源),您仍然需要解开它们.见-T
在perlrun文档和perlsec文档.
如果需要读取输出或向命令发送输入,qx
并且readpipe
没有等效项.相反,使用open my $output, "-|", $cmd, @args
或open my $input, "|-", $cmd, @args
虽然这是不可移植的,因为它需要一个真正的fork
,这意味着只有...我想.也许它可以在Windows上使用它的模拟分支.一个更好的选择就像IPC :: Run,它也可以处理管道命令到其他命令的情况,系统的多arg形式和open的4 arg形式都不会处理.
在Windows上,情况有点糟糕.基本上,所有的Win32程序收到一个长命令行字符串-壳(通常cmd.exe
)可以首先做一些解释,消除<
和>
例如重定向,但它并没有在该程序字边界分裂它.每个程序都必须自己进行解析(如果他们愿意 - 有些程序不会打扰).在C和C++程序中,由编译器工具链提供的运行时库提供的例程通常在main()
调用之前执行此解析步骤.
问题是,通常,您不知道给定程序将如何解析其命令行.许多程序都是使用某些版本的MSVC++编译的,其中描述了古怪的解析规则,但许多其他程序使用不同的编译器编译,这些编译器使用不同的约定.
cmd.exe
具有其自身古怪的解析规则的事实加剧了这一点.caret(^
)被视为引用以下字符的转义字符,如果满足棘手条件列表,则双引号内的文本将被视为引用(cmd /?
有关完整的详细信息,请参阅参考资料).如果你的命令包含任何奇怪的字符,那么很容易cmd.exe
知道哪些部分的文字被"引用",哪些不会与你的目标程序不同步,而且所有的地狱都会破裂.
因此,在Windows上转义参数的最安全方法是:
以您正在调用的程序的命令行解析逻辑所期望的方式转义参数.(希望你知道那个逻辑是什么;如果没有,试试几个例子并猜测.)
使用空格加入转义参数.
使用生成字符串的每个非字母数字字符前缀^
.
附加任何重定向或其他shell欺骗(例如,加入命令&&
).
使用system()
或反引号运行命令.