Perl逃脱bash执行的参数

我用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'
 [和! 历史扩张标志]给出
        “与! 历史扩张标志“
 []给出
        ''
 [一些周围的空间]给
        “一些周边空间”