如何使用system()避免在Perl中意外逃逸?

0 perl system

我想使用system()命令运行一些命令,我这样做:

execute_command_error("trash-put '/home/$filename'");
Run Code Online (Sandbox Code Playgroud)

如果运行的execute_command_error任何system命令出现错误,将在何处报告.我知道我可以使用Perl命令取消链接文件,但我想删除使用的东西,trash-put因为它是一种回收程序.

我的问题是,$filename有时会出现撇号,引号和其他奇怪的字符,这些字符会破坏system命令或Perl本身.

Jon*_*ler 5

生成命令名称和参数作为数组,并将其传递给系统:

my(@command) = ("trash-put", 'home/$filename');
system @command;
Run Code Online (Sandbox Code Playgroud)

这意味着Perl不会调用shell来执行任何元字符扩展(或I/O重定向,或命令管道,或......).它确实意味着它完全按照你的要求去做.

sub execute_command_error
{
    system @_;
}
Run Code Online (Sandbox Code Playgroud)

从大量评论中借用信息:

这是在明确记载perldoc -f systemperldoc.perl.org/functions/system.html(@Ether).

(另见下面关于'exec'的讨论密切相关.)

你的意思是将$ filename放在单引号中吗?(@mobrule).

我确实打算使用单引号 - 我正在证明它$filename不会被Perl或Shell扩展...在我的测试脚本中,我使用了' my.$file',这给了我一个$名字中带有a的文件- 就像我打算的那样.

我认为如果你想调用shell(例如,如果你想要一些管道),所需的引用是$ command_line ="\"$ command \"\"$ arg1 \"\"$ arg2 \"...".(@Jefromi).

在参数周围添加双引号对嵌入式$,反引号1,$(...)'和相关表示法没有帮助.你几乎需要单引号,但是你需要将嵌入的单引号重写为" '\''",它会生成一个单引号来终止当前的单引号参数,一个反斜杠报价组合来表示单引号,另一个单引号恢复单引号参数.

如果我直接使用系统命令,这将是一个很好的解决方案; 但是我使用webmin的execute_command功能,这有点过头了,所以我不知道如何编辑它以允许数组.您是否可以将嵌入式单引号的重写扩展为" '\''"......这就是我现在要使用的内容.(@布赖恩)

粗略地说,(Unix)shell处理单引号的方式是"从第一个单引号到下一个引用的所有内容都是文字文本,没有元字符".因此,要使shell将某些内容视为文字文本,请将其括在单个字符中.这涉及除单引号本身以外的所有内容.正如我的评论所说,你必须使用4个字符的替换字符串来将单个引号嵌入到单个引用参数的中间.

可能有一种比这更简洁的方法(可能使用一个或两个map操作),但这应该有效:

for (my $i = 0; $i < scalar(@command); $i++)
{
    $command[$i] =~ s/'/'\\''/g; # Replace single quotes by the magic sequence
    $command[$i] = "'$command[$i]'"; # Wrap value in single quotes
}
Run Code Online (Sandbox Code Playgroud)

然后,您可以加入数组以生成单个字符串以进行传输execute_command.


最好将其写成系统{$ command [0]} @command来处理@command有一个元素的情况.这是我在Mastering Perl的"安全编程技术"一章中谈到的事情之一.(@briandfoy).

作为一般规则,我会接受这种更正.但是,我不确定在这种情况下它是至关重要的,其中命令名称由程序提供,并且它只是可能为用户提供的参数.命令名称'trash-put'对于shell扩展是安全的(shell启动时IFS将被重置为默认值,因此攻击途径不可用).

这个问题在'perldoc -f exec'手册页中讨论:

如果你真的不想执行第一个参数,但是想要对你正在执行的程序撒谎,你可以指定你真正想要作为"间接对象"(没有逗号)运行的程序列表的前面.(这总是强制将LIST解释为多值列表,即使列表中只有一个标量.)

例:

   $shell = '/bin/csh';
   exec $shell '-sh'; # pretend it's a login shell
Run Code Online (Sandbox Code Playgroud)

或者,更直接地,

   exec {'/bin/csh'} '-sh'; # pretend it's a login shell
Run Code Online (Sandbox Code Playgroud)

当参数通过系统shell执行时,结果受其怪癖和能力的影响.有关STRING详细信息,请参阅perlop中的" ".

使用带有exec或system的间接对象也更安全.这种用法(对于system()也可以正常工作)强制将参数解释为多值列表,即使列表只有一个参数.这样你就可以安全地从shell扩展通配符或拆分带有空格的单词.

   @args = ( "echo surprise" );
   exec @args;              # subject to shell escapes
                            # if @args == 1
   exec { $args[0] } @args; # safe even with one-arg list
Run Code Online (Sandbox Code Playgroud)

第一个版本,没有间接对象的版本,运行echo程序,将其"惊喜"传递给它.第二个版本没有; 它试图运行一个名为"echo surprise"的程序,没找到它,并设置$?到表示失败的非零值.


1如何在Markdown中显示后退?

  • ...在'perldoc -f system`中有明确记载:http://perldoc.perl.org/functions/system.html (2认同)