system(“echo -e $ str”)无法在perl中正确输出

时间:2016-03-15 06:23:47

标签: perl echo system

我写了一个像这样的简单perl脚本

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

,输出为:

-e hello
sh: 2: world: not found

这是不期望的。我想要的是这个:

hello
world

注意“echo -e”可以正常工作,因为当我运行以下命令时,

echo -e "hello\nworld"

输出正确。

任何解决方案?

2 个答案:

答案 0 :(得分:5)

如果您在设置后打印$cmd,则会看到:

echo -e hello
world

...如果您将其粘贴到shell中,您会收到类似的错误消息,尽管没有-e

第一个问题是,当它到达shell时,字符串缺少引号和非文字换行符。试试这个:

my $str = "hello\\nworld";
my $cmd = "echo -e '$str'";

在这种特殊情况下,你可以只使用引号 - 在echo的参数中会有一个字面换行符,但只要引用它就是合法的

但是,您仍会在输出中获得文字-e,并且不会将\n解释为换行符。这是因为perl正在运行/bin/echo,而不是内置在bash中的echo。如果你想使用bash的内置,你必须告诉perl明确地运行bash。但这意味着将echo命令本身传递给bash中的参数,这引入了另一个级别的引用来处理。

这里最好的赌注(实际上是无处不在)是使用system的多参数版本;绕过第一个shell级别并直接执行命令。我们仍然需要处理换行符:

my $str = "hello\nworld";                 # literal newline
(my $escaped_str = $str) =~ s,\n,\\n,g;    # escaped newline

为了从shell获得所需的行为,我们需要在shell命令中将字符串嵌入单引号中,因为单引号中的任何内容都完全由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:

system('bash', '-c', $command);

总的来说,更重要的是,我会考虑将shell命令替换为Perl本身的代码;结果将更容易管理,并且可能更便携和更高效。

答案 1 :(得分:0)

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

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