如何在perl系统函数中使用两个管道并防止shell扩展?

Wak*_*nka -1 shell perl system pipe variable-expansion

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

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

# RESULT
*
Run Code Online (Sandbox Code Playgroud)

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

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

# RESULT
Desktop Documents Downloads
Run Code Online (Sandbox Code Playgroud)

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

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

# RESULT
1 Desktop Documents Downloads
Run Code Online (Sandbox Code Playgroud)

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

我试过了:

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

# RESULT
* | cat -n
Run Code Online (Sandbox Code Playgroud)

但由于我上面描述的原因(多个参数未扩展),这不起作用.我想要的结果是:

1 *
Run Code Online (Sandbox Code Playgroud)

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

system("echo \"$email_message\" | mailx -s \"$email_subject\" $recipient");
Run Code Online (Sandbox Code Playgroud)

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

ike*_*ami 5

system 有三个调用约定:

system($SHELL_CMD)

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

system( { $PROG } $NAME, @ARGS )   # @ARGS>=0
Run Code Online (Sandbox Code Playgroud)

第一个命令传递给shell.它相当于

system('/bin/sh', '-c', $SHELL_CMD)
Run Code Online (Sandbox Code Playgroud)

另外两个执行程序$PROG.system永远不会阻止shell扩展或执行任何转义.根本没有涉及到shell.

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

echo \* | cat -n
Run Code Online (Sandbox Code Playgroud)

要么

echo '*' | cat -n
Run Code Online (Sandbox Code Playgroud)

通过*.*在插值之前,您需要一个执行转义工作的函数.幸运的是,一个已经存在:字符串:: 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  *
Run Code Online (Sandbox Code Playgroud)

我使用printf而不是echo因为从-in 开始处理参数非常困难echo.大多数程序接受--将选项与非选项分开,但不接受我的选项echo.

所有这些并发症都提出了一个问题:你为什么要发送电子邮件?处理来自外部程序的错误通常比从库中处理错误要困难得多.