如何在perl系统功能中同时使用两个管道并防止shell扩展? [英] How to use both pipes and prevent shell expansion in perl system function?

查看:95
本文介绍了如何在perl系统功能中同时使用两个管道并防止shell扩展?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如果将多个参数传递给perl的系统函数,则shell扩展将无法工作:

If multiple arguments are passed to perl's system function then the shell expansion will not work:

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

# RESULT
*

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

If the command is passed as an one argument then the expansion will work:

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

# RESULT
Desktop Documents Downloads

系统功能还允许使用多个命令并使用管道连接它们.仅当将参数作为一个命令传递时,此方法才有效:

The system function also allows to using multiple commands and connect them using pipes. This only works when argument is passed as an one command:

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

# RESULT
1 Desktop Documents Downloads

如何结合提到的命令并同时使用两个管道并防止Shell扩展?

How can I combine mentioned commands and use both pipes and prevent shell expansion?

我尝试过:

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

# RESULT
* | cat -n

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

but this did not work because of reasons that I've described above (multiple arguments are not expanded). The result that I want is:

1 *

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

The problem that I'm actually facing is that when I use following command:

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

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

Then the $email_message is expanded and it will break mailx if it contains some characters that are further expanded by shell.

推荐答案

system具有三个调用约定:

system($SHELL_CMD)

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

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

第一个将命令传递给外壳.等同于

The first passes a command to the shell. It's equivalent to

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

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

The other two execute the program $PROG. system never prevents shell expansion or performs any escaping. There's simply no shell involved.

因此,您的问题是关于构建Shell命令.如果出现提示,则可以使用

So your question is about building a shell command. If you were at the prompt, you might use

echo \* | cat -n

echo '*' | cat -n

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

to pass *. You need a function that performs the job of escaping * before interpolating it. Fortunately, one already exists: String::ShellQuote's shell_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,因为很难处理echo中以-开头的参数.大多数程序都接受--来将选项与非选项分开,但是我的echo则不能.

I used printf instead of echo since it's very hard to handle arguments starting with - in echo. Most programs accept -- to separate options from non-options, but not my echo.

所有这些复杂问题都引出了一个问题:您为什么要炮轰发送电子邮件?通常,处理外部程序中的错误比处理库中的错误要困难得多.

All these complications beg the question: Why are you shelling out to send an email? It's usually much harder to handle errors from external programs than from libraries.

这篇关于如何在perl系统功能中同时使用两个管道并防止shell扩展?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆