【发布时间】:2011-03-13 19:57:41
【问题描述】:
为了转义用作 shell 参数的字符串,我们在 PHP 中使用函数 escapeshellarg()。 Perl 有等效功能吗?
【问题讨论】:
为了转义用作 shell 参数的字符串,我们在 PHP 中使用函数 escapeshellarg()。 Perl 有等效功能吗?
【问题讨论】:
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);
【讨论】:
ls 'f o o' 的以下失败尝试的解决方案:my $foo='f o o'; my $result = `ls $foo 2>&1`; ?
use IPC::System::Simple qw(systemx EXIT_ANY $EXITVAL); systemx(EXIT_ANY, $command, @arguments); 将防止异常并在$EXITVAL 中指示成功。见IPC::System::Simple#ADVANCED_SYNOPSIS
Perl 可以匹配下面的声明函数:
在字符串周围添加单引号并引用/转义任何现有的单引号
http://php.net/manual/en/function.escapeshellarg.php#function.escapeshellarg
像这样:
sub php_escapeshellarg {
my $str = @_ ? shift : $_;
$str =~ s/((?:^|[^\\])(?:\\\\)*)'/$1'\\''/g;
return "'$str'";
}
【讨论】:
foo'bar 传递给函数。它将产生以下字符串:'foo\'bar'。但是单引号内不能有转义的单引号。
我必须同意@daxim。但是在某些情况下您不能使用它,例如通过套接字将命令传递给不是 perl 或没有可用 IPC 模块的程序。我还查看了@axeman 给出的正则表达式,这对我来说似乎有点复杂。我可能是错的,但我认为您不需要为命令转义单引号字符串中的反斜杠。所以,你可以这样做:
sub escapeshellarg {
my $arg = shift;
$arg =~ s/'/'\\''/g;
return "'" . $arg . "'";
}
如果有人有任何理由,为什么这可能不安全,我想知道。我已经使用我能想到的任何技巧对其进行了测试,以使 shell 执行任意代码,但没有成功,这让我认为这个正则表达式与 PHP 实现相同。
在 PHP 实现中,它声明它所做的只是:在字符串周围添加单引号并引用/转义任何现有的单引号。
这是这个正则表达式唯一做的事情。 想法?
【讨论】:
这个在 BASH 中对我有用:
sub escape_shell_param($) {
my ($par) = @_;
$par =~ s/'/'"'"'/g; # "escape" all single quotes
return "'$par'"; # single-quote entire string
}
它基于 BASH 手册页中的以下语句:
- 用单引号括起来的字符会保留引号内每个字符的字面值。
- 单引号之间不能出现单引号,即使前面有反斜杠。
- 将字符括在双引号中会保留引号内所有字符的字面值,但 $、`、 \,并且,当启用历史扩展时,!。
从 (2.) 我们知道反斜杠不能用于转义单引号,但从 (3.) 可以看出,双引号会保留(也称为转义)单引号的字面值。
还要注意引号的唯一目的是改变引号字符的含义(不创建特殊的字符串对象或类似的东西),并且在扩展后所有连续的文字字符都连接在一起。那么'foo''bar'就等于foobar。
上面的函数所做的是对整个字符串进行单引号,这样其中的字符就没有特殊含义了。但是,为了允许单引号字符的存在,字符串会在找到此类字符的任何位置进行拆分,并完成以下操作:前一个子字符串完成('),然后引入双引号单引号( "'") 并开始下一个子字符串 (')。这就是为什么' 被全局替换为'"'"'。
例如(伪代码):
foo'bar => 'foo' + "'" + 'bar'
【讨论】: