2010-07-09 108 views

回答

30

String::ShellQuote,但大多数时候这是不需要的。您可以通过仔细编程来避免调用shell。例如,system takes a list of arguments而不是字符串。

最佳实践:

use IPC::System::Simple qw(systemx); 
systemx($command, @arguments); 

require IPC::System::Simple; 
use autodie qw(:all); 
system([@allowed_exit_values], $command, @arguments); 
+5

是的,就避免了壳完全如果在所有可能的。 – 2010-07-09 11:49:44

+3

用适当的解决方案回答[XY问题](http://www.perlmonks.org/index.pl?node_id=542341)的好工作。 :) – Ether 2010-07-09 15:07:08

+0

这可以帮助,但当你需要重定向(所以不能使用系统()调用的列表形式)*和*变量参数?例如一个解决以下失败的尝试'ls'f o o''的方法:'my $ foo ='f o o';我的$结果= \'ls $ foo 2> &1\';'? – artfulrobot 2014-04-23 11:04:49

3

Perl可以匹配以下功能:

增加将字符串和报价单引号/逃脱任何现有的单引号

http://php.net/manual/en/function.escapeshellarg.php#function.escapeshellarg

这样的:

sub php_escapeshellarg { 
    my $str = @_ ? shift : $_; 
    $str =~ s/((?:^|[^\\])(?:\\\\)*)'/$1'\\''/g; 
    return "'$str'"; 
} 
+1

这不起作用。考虑将字符串“foo'bar”传递给函数。它会产生以下字符串:''foo \'bar''。但在单引号内不能有单引号。 – josch 2016-04-23 09:54:12

0

我有@daxim同意。但是在某些情况下,您不能像使用套接字将命令传递给不是perl的程序或没有可用的IPC模块那样使用它。我也看了@axeman给出的正则表达式,这对我来说似乎有点复杂。我可能是错的,但我认为你不需要在单引号字符串中为一个命令避开反斜杠。所以,你可以这样做:

sub escapeshellarg { 
    my $arg = shift; 

    $arg =~ s/'/'\\''/g; 
    return "'" . $arg . "'"; 
} 

如果任何人有任何理由,为什么这可能是不安全的,我想知道。我已经使用任何可以想到使外壳执行任意代码而没有成功的欺骗来测试它,这使我认为这个正则表达式与PHP实现相同。

在PHP实现中,它声明它所做的只是:围绕字符串添加单引号,引号/转义任何现有的单引号。

这是这个正则表达式唯一的东西。 想法?

+2

我很怀疑,我总是更喜欢cagedtesters验证的[String :: ShellQuote](http://p3rl.org/String::ShellQuote),它已经在野外部署了多年,并且有错误报告和修复程序通过SO用户的ad-hoc正则表达式来显示它。你可以将它的代码与你的代码进行比较,并找出你自己缺乏的东西。 – daxim 2012-05-28 14:46:51

+0

@daxim他们不太容易比较:http://api.metacpan.org/source/ROSCH/String-ShellQuote-1.04/ShellQuote.pm – dlamblin 2012-10-16 15:17:23

+0

该死,对不起,我不小心downvoted你的答案,现在我无法撤消它。 :( – josch 2016-04-23 10:03:03

1

这一个适用于我在BASH:

sub escape_shell_param($) { 
    my ($par) = @_; 
    $par =~ s/'/'"'"'/g; # "escape" all single quotes 
    return "'$par'";  # single-quote entire string 
} 

它是基于从BASH手册页采取了以下声明:

  1. 在单引号围护字符保留的字面意义引号内的每个字符。
  2. 单引号之间可能不会出现单引号,即使前面带有反斜杠。
  3. 用双引号括起来的字符保留了引号中所有字符的字面值,除了$,`, \,并且当启用历史扩展时!!

From(2。)我们知道反斜杠不能用于转义单个qoutes,但是从(3)中可以看出,双引号保留了(又名转义)单引号的文字值。

还要注意的是报价的唯一目的是改变引用的字符的含义(不创建特殊的字符串对象或类似的东西)和扩张毕竟连续的文字字符连接在一起。然后,'foo''bar'foobar相同。

上面的函数做了什么是单引号整个字符串,以便没有特殊含义的字符。但是,为了允许存在单引号字符,字符串会在发现此类字符的任何位置被拆分,并执行以下操作:前一个子字符串已完成('),然后引入一个双引号单引号("'")并开始下一个子字符串(')。这就是为什么'全球取代'"'"'

例如(伪代码):

foo'bar => 'foo' + "'" + 'bar'