-1

如果将多个参数传递给 perl 的系统函数,那么 shell 扩展将不起作用:

# COMMAND
$ perl -e 'my $s="*"; system("echo", "$s" )'

# RESULT
*

如果命令作为一个参数传递,则扩展将起作用:

# COMMAND
$ perl -e 'my $s="echo *"; system("$s")'

# RESULT
Desktop Documents Downloads

系统功能还允许使用多个命令并使用管道连接它们。这仅在参数作为一个命令传递时才有效:

# COMMAND
$ perl -e 'my $s="echo * | cat -n"; system("$s")'

# RESULT
1 Desktop Documents Downloads

如何组合提到的命令并使用两个管道并防止外壳扩展?

我努力了:

# COMMAND
$ perl -e 'my $s="echo"; system("$s", "* | cat -n")'

# RESULT
* | cat -n

但这不起作用,因为我上面描述的原因(多个参数没有展开)。我想要的结果是:

1 *

编辑:我实际面临的问题是当我使用以下命令时:

system("echo \"$email_message\" | mailx -s \"$email_subject\" $recipient");

然后 $email_message 被扩展,如果它包含一些由 shell 进一步扩展的字符,它将破坏 mailx。

4

2 回答 2

5

system有三个调用约定:

system($SHELL_CMD)

system($PROG, @ARGS)               # @ARGS>0

system( { $PROG } $NAME, @ARGS )   # @ARGS>=0

第一个将命令传递给 shell。相当于

system('/bin/sh', '-c', $SHELL_CMD)

另外两个执行程序$PROGsystem从不阻止外壳扩展或执行任何转义。根本不涉及外壳。

所以你的问题是关于构建一个shell命令。如果您在提示符下,您可以使用

echo \* | cat -n

或者

echo '*' | cat -n

通过**您需要一个在插入之前执行转义工作的函数。幸运的是,已经存在一个:String::ShellQuoteshell_quote

$ perl -e'
   use String::ShellQuote qw( shell_quote );
   my $s = "*";
   my $cmd1 = shell_quote("printf", q{%s\n}, $s);
   my $cmd2 = "cat -n";
   my $cmd = "$cmd1 | $cmd2";
   print("Executing <<$cmd>>\n");
   system($cmd);
'
Executing <<printf '%s\n' '*' | cat -n>>
     1  *

我使用printf而不是echo因为很难处理以 in 开头的-参数echo。大多数程序都接受--将选项与非选项分开,但我的echo.

所有这些复杂性都引出了一个问题:您为什么要花大价钱发送电子邮件?处理来自外部程序的错误通常比处理来自库的错误要困难得多。

于 2015-04-12T23:53:05.677 回答
3

您可以使用open管道直接连接到 mailx,而外壳不会解释您的内容:

open( my $mail, "|-", "mailx", "-s", $email_subject, $recipient );
say $mail $email_message;
close $mail;

更多细节可以在perlipc的开放部分找到。

于 2015-04-12T22:25:54.087 回答