如果打印出来$cmd
你设置后,你会看到这一点:
echo -e hello
world
...如果你粘贴到壳,你会得到类似的错误消息,虽然没有-e
。
第一个问题是,当它到达shell时,该字符串缺少引号和非文字换行符。试试这个:
my $str = "hello\\nworld";
my $cmd = "echo -e '$str'";
在这种特殊情况下,你可以逃脱只是引号 - 将会有参数echo
内文字换行,但只要它引用了这是合法的。
但是,您仍然会在输出中获得立即数-e
,并且不会将\n
解释为换行符。这是因为perl运行的是/bin/echo
,而不是内置于bash的echo
。如果你想使用bash的builtin,你必须告诉perl明确运行bash
。但这意味着将echo命令本身内部的参数传递给bash,从而引入另一个级别的引用来处理。
这里最好的选择是使用system
的多重参数版本;它绕过第一个shell级别并直接执行该命令。我们还必须应对新行:
my $str = "hello\nworld"; # literal newline
(my $escaped_str = $str) =~ s,\n,\\n,g; # escaped newline
为了从壳获得所需的行为,我们需要嵌入在shell命令单引号括起来的,因为在单引号里的东西被认为完全从字面上由壳。在这种情况下,我们只是从Perl代码中的文字中分配字符串,所以我们知道它包含的内容,并且不包含撇号。但是,如果它可能永远包含撇,我们应该运行它通过另一个逃生传球给说出来了,所以它的安全在单引号嵌入:
$escaped_str =~ s,','\\'',g; # quote any embedded apostrophes
有可能是你希望与逃逸替换其他字符,太 - 也许标签或回车。这将是进行这些更改的地方。
使用转义字符串建立bash命令:
my $command = "echo -ne '$escaped_str'"; # bash command to echo string
手工做搜索/替换这样很容易出错;有很多边缘案例需要考虑。所以,你可能也想看看CPAN模块String::ShellQuote
,在其中您可以跳过手动上述逃逸,从原始这样的转义字符串:
my $command = shell_quote("echo", "-ne", $str);
一旦你有逃脱的命令字符串,请使用
system('bash', '-c', $command);
一般,更重要的是,我会考虑更换任何shell命令用Perl本身代码的功能;:多参数system
直接与该字符串作为参数运行的bash结果将更容易管理,并且可能更具可移植性和性能。
因为'echo -e'不是可移植的,所以这是一个特别糟糕的例子。对于任何真实的东西,'echo'都可以做到,你可以在Perl中更简单地做到这一点。也许你应该使用一个不同的例子,或许更接近你想要运行的真实代码。 – tripleee