我写了一个像这样的简单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"
输出正确。
任何解决方案?
答案 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");
系统参数字符串中的新行就像;
。它分离命令。为了不发生这种情况,你需要把它放在引号内。