我用Perl编写了一些代码,在执行中执行一些bash命令。 我的问题是,当bash命令属性包含白色空间内的bash命令执行失败。 但是我已经设法使用这些参数来简单地在引数上加引号。 不幸的是,在testing过程中,我发现当\
字符放在variables的末尾时,我的脚本失败了,这明显会导致bash执行引号和bash命令失败。 例如:
my $arg1 = 'This is sample text which can be put into variable. And a random sign\\'; `echo "$arg1"`
有没有机会自动转义variables中的特殊字符?
在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使用许多管道和东西:
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调用这个脚本。
我发现把命令变成一个变量比使用反引号运行起来更容易,只是因为引号不好:
my $bash_command = "echo 'This is sample text ending in a slash \\'"; print `$bash_command`; # `` brings the result back into Perl instead of to STOUT
使用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,不要在参数周围放置任何引号。
正如Glenn Jackman所说,当直接从perl调用时,我会使用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]给出 '你好,世界' [Hello World!]给出 '你好,世界!' [Nothing_special_here.txt]给出 'Nothing_special_here.txt' [With'One Single Quote]给出 $(echo'With'''''One Single Quote') [与'两单'行情]给 $(echo'With'“'”'Two Single'''''Quotes') ['与周围的单引号]给出 $(echo''''''与周围的单引号'''''') [用$美元符号]给出 '有$美元符号' [用* Fileglob]给出 '用* Fileglob' [和! 历史扩张标志]给出 “与! 历史扩张标志“ []给出 '' [一些周围的空间]给 “一些周边空间”