2016-03-15 60 views
0

我写这样

#!/usr/bin/perl 
my $str = "hello\nworld"; 
my $cmd = "echo -e $str"; 
system($cmd); 

,并输出一个简单的Perl脚本是:预计不

-e hello 
sh: 2: world: not found 

。而我想是这样的:

hello 
world 

指出,“回声-e”能工作correclty,因为当我运行下面的命令,

echo -e "hello\nworld" 

输出是正确的。

任何解决方案?

+1

因为'echo -e'不是可移植的,所以这是一个特别糟糕的例子。对于任何真实的东西,'echo'都可以做到,你可以在Perl中更简单地做到这一点。也许你应该使用一个不同的例子,或许更接近你想要运行的真实代码。 – tripleee

回答

5

如果打印出来$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结果将更容易管理,并且可能更具可移植性和性能。

+0

thx,当我使用你的推荐命令时,输出是这样的: '-e你好 world' 但是当删除'-e'选项('“ehco $ cmd =”echo'$ str'“')时,可以正常工作。 – user6064254

+1

继续阅读..我覆盖了。 –

0
my $cmd = qq(echo -e "$str"); 

系统参数字符串中的新行类似于;。它分隔命令。为了不发生这种情况,你需要把它放在引号内。