我应该在Perl中转义shell参数吗?

时间:2009-03-06 18:33:04

标签: perl shell arguments

在Perl中使用system()调用时,是否必须转义shell args,还是自动完成?

参数将是用户输入,因此我想确保这不会被利用。

5 个答案:

答案 0 :(得分:37)

如果使用system $cmd, @args而不是system "$cmd @args"(数组而不是字符串),那么您不必转义参数,因为没有调用shell(请参阅system)。即使$ cmd包含元字符且@args为空(exec的一部分记录),system {$cmd} $cmd, @args也不会调用shell。如果args来自用户输入(或其他不受信任的来源),您仍然需要解开它们。请参阅perlrun文档中的-Tperlsec文档。

如果您需要阅读输出或向命令发送输入,qxreadpipe没有相应的内容。相反,使用open my $output, "-|", $cmd, @argsopen my $input, "|-", $cmd, @args虽然这不可移植,因为它需要一个真正的fork,这意味着只有Unix ......我想。也许它可以在Windows上使用它的模拟分支。更好的选择是IPC::Run,它也可以处理将命令发送到其他命令的情况,系统的多参数形式和4参数形式的open都不会处理。

答案 1 :(得分:13)

在Windows上,情况有点糟糕。基本上,所有Win32程序都会收到一个长命令行字符串 - shell(通常是cmd.exe)可以先做一些解释,例如删除<>重定向,但它确实< em> not 将它拆分为程序的字边界。每个程序都必须自己进行解析(如果他们愿意 - 有些程序不会打扰)。在C和C ++程序中,随编译器工具链提供的运行时库提供的例程通常会在调用main()之前执行此解析步骤。

问题是,通常,您不知道给定程序将如何解析其命令行。许多程序是使用某些版本的MSVC ++编译的,其quirky parsing rules are described here,但许多其他程序使用不同的编译器编译,使用不同的约定。

cmd.exe有自己古怪的解析规则,这使事情更加复杂。插入符号(^)被视为引用后续字符的转义字符,如果满足棘手条件列表,则双引号内的文本将被视为引用(有关完整的详细信息,请参阅cmd /? )。如果你的命令包含任何奇怪的字符,那么cmd.exe很容易知道哪些部分的文本被“引用”,哪些不会与你的目标程序不同步,而且所有的地狱都会破裂。

因此,在Windows上转义参数最安全的方法是:

  1. 以您正在调用的程序的命令行解析逻辑所期望的方式转义参数。 (希望你知道那个逻辑是什么;如果不是,试试几个例子并猜测。)
  2. 使用空格加入转义参数。
  3. 使用^为结果字符串前缀每个非字母数字字符
  4. 附加任何重定向或其他shell欺骗(例如,使用&&加入命令)。
  5. 使用system()或反引号运行命令。

答案 2 :(得分:2)

 sub esc_chars {
  # will change, for example, a!!a to a\!\!a
     @_ =~ s/([;<>\*\|`&\$!#\(\)\[\]\{\}:'"])/\\$1/g;
     return @_;
  }

http://www.slac.stanford.edu/slac/www/resource/how-to-use/cgi-rexx/cgi-esc.html

答案 3 :(得分:1)

如果使用系统“$ cmd @args”(字符串),则必须转义参数,因为调用了shell。

幸运的是,对于双引号字符串,只需要转义四个字符:

"    - double quote
$    - dollar
@    - at symbol
\    - backslash

答案 4 :(得分:0)

你问题的答案非常有用。最后,我按照@ runrig的建议,然后使用核心模块open3()命令,这样我就可以捕获STDERR和STDOUT的输出。

对于与@ runrig解决方案一起使用的open3()的示例代码,请参阅我的相关问题和答案:
Calling system commands from Perl