[英]Perl escaping argument for bash execution
我在Perl中编写了一些代码,它在执行过程中执行一些bash命令。 我的问题是当bash命令属性包含空格时,bash命令执行失败。 但我已经设法使用这些参数简单地在参数周围添加引号。 不幸的是在测试期间我发现我的脚本在\\
字符放在变量的末尾时失败,这明显地逃脱了bash执行引用并且失败了bash命令。 例如:
my $arg1 = 'This is sample text which can be put into variable. And a random sign\\';
`echo "$arg1"`
有没有机会自动转义变量中的特殊字符?
在bash中使用单引号要容易得多; 那么你需要担心的唯一一个角色就是单引号本身。
($arbitrary_string) =~ s/'/'"'"'/g;
`echo '$arbitrary_string'`
CPAN来救援。
String :: ShellQuote应该做你需要的,尽管我同意@glennjackman system
(或Capture :: Tiny )是一种更好的方法:
use String::ShellQuote 'shell_quote';
my $cmd = shell_quote( 'echo', 'This is sample text ending in a slash \\' );
`$cmd`;
不要使用反引号来保持你的字符串远离shell,因此所有引用问题:
system 'echo', $var;
你写:
不幸的是,我需要这个命令的stdout。 另一件事是变量用于lil bit complex命令,它使用了许多管道和东西:
echo $var | sed | grep | awk | and so on... and so on...
echo $var | sed | grep | awk | and so on... and so on...
您可能想要使用类似的东西进行调查(未经测试,主要来自IPC :: Open3 perldoc)
use IPC::Open3;
use Symbol 'gensym';
my ($wtr, $rdr, $err);
$err = gensym;
my $pid = open3($wtr, $rdr, $err, 'sed|grep|awk|and so on');
print $wtr $var;
close $wtr;
my $output = <$rdr>;
waitpid $pid, 0;
如果您的管道非常混乱,请将其存储在shell脚本文件中,并从perl调用该脚本。
使用quotemeta :
my $arg1 = quotemeta('string to be escaped');
`echo $arg1`
或\\Q\\E
(这正是quotemeta);
my $arg1 = 'string to be escaped';
`echo \Q$arg1\E`
另请注意,使用echo
是打印任意字符串的一种不好的方法 。
如果您使用的是quotemeta,请不要在参数周围添加任何引号。
当直接从perl调用时,正如Glenn Jackman所说,我会使用system或exec来避免引用麻烦并捕获输出,例如计算文件的md5sum:
my $pid, $safe_kid;
die "cannot fork: $!" unless defined ($pid = open($safe_kid, "-|"));
if ($pid == 0) {
# This is the child process, exec md5sum
exec('/usr/bin/md5sum', '--binary', $filename) or die "can't exec md5sum: $!";
} else {
# This is the parent process, read data (we do not need to wait for
# child process termination)
@sum = <$safe_kid>;
close $safe_kid; # $? contains status
}
if ($?!=0) {
die "Problem computing hashsums on '$filename': $!\n";
}
在相关的说明中,我一直在寻找一种方法来打印命令行参数到shell以供用户复制和粘贴。 我想到了单引一切,并使用echo
重新组合字符串,如果单引号已经存在,虽然使用String :: ShellQuote似乎是一个更好的主意,真的:
#!/usr/bin/perl
use strict;
testEscapeForBash("Hello World");
testEscapeForBash("Hello World!");
testEscapeForBash("Nothing_special_here.txt");
testEscapeForBash("With'One Single Quote");
testEscapeForBash("With 'Two Single' Quotes");
testEscapeForBash("'With Surrounding Single Quotes'");
testEscapeForBash("With \$ Dollar Sign");
testEscapeForBash("With * Fileglob");
testEscapeForBash("With ! History Expansion Sign");
testEscapeForBash(" ");
testEscapeForBash(" Some surrounding spaces ");
sub testEscapeForBash {
my ($in) = @_;
my $out = escapeForBash($in);
print "[$in] gives\n $out\n";
}
sub escapeForBash {
my ($name) = @_;
if (!$name) {
die "Empty name passed to 'escapeForBash'"
}
my @parts = split(/'/,$name,-1); # limit is negative to catch trailing quote
my $res;
if (@parts == 1) {
$res = "'$name'"
}
elsif (@parts > 1) {
$res = '$(echo ';
my $first = 1;
for my $part (@parts) {
$res .= "\"'\"" unless $first;
$first = 0;
$res .= "'";
$res .= $part;
$res .= "'";
}
$res .= ')';
}
else {
die "Weird number of parts: @parts"
}
return $res
}
我们运行这个:
[Hello World] gives 'Hello World' [Hello World!] gives 'Hello World!' [Nothing_special_here.txt] gives 'Nothing_special_here.txt' [With'One Single Quote] gives $(echo 'With'"'"'One Single Quote') [With 'Two Single' Quotes] gives $(echo 'With '"'"'Two Single'"'"' Quotes') ['With Surrounding Single Quotes'] gives $(echo ''"'"'With Surrounding Single Quotes'"'"'') [With $ Dollar Sign] gives 'With $ Dollar Sign' [With * Fileglob] gives 'With * Fileglob' [With ! History Expansion Sign] gives 'With ! History Expansion Sign' [ ] gives ' ' [ Some surrounding spaces ] gives ' Some surrounding spaces '
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.