How to use both pipes and prevent shell expansion in a perl system function?

If multiple arguments are passed to a perl system function, the shell extension won't work:

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

# RESULT
*

      

If the command is passed as one argument, the extension will work:

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

# RESULT
Desktop Documents Downloads

      

The system function also allows multiple commands to be used and connected using pipes. This only works when the argument is passed as one command:

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

# RESULT
1 Desktop Documents Downloads

      

How can I combine the above commands and use both pipes and prevent the shell from expanding?

I tried:

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

# RESULT
* | cat -n

      

but it didn't work due to the reasons I described above (multiple arguments not expanded). As a result, I want:

1 *

      

EDIT: The problem I am facing is that when I use the following command:

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

      

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

-1


source to share


2 answers


system

has three calling conventions:

system($SHELL_CMD)

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

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

      

The first passes the command to the shell. This is equivalent to

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

      

The other two execute the program $PROG

. system

never prevents the shell from expanding or does any kind of escaping. There is simply no shell involved.

So your question is about creating a shell command. If you were on the command line, you can use

echo \* | cat -n

      



or

echo '*' | cat -n

      

transfer *

. You will need a function to do the acceleration task *

before interpolating it. Fortunately, there is already: String :: ShellQuote 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  *

      

I used printf

instead echo

as it is very difficult to handle arguments starting with -

in echo

. Most programs accept --

to separate options from non-parameters, but not my echo

.

All of these complications raise the question: why are you shelling to send an email? It is usually much more difficult to handle errors from external programs than from libraries.

+5


source


You can use open

to connect directly to mailx without your content being interpreted by the shell:

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

      



More details can be found in the open section of perlipc .

+3


source







All Articles