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.
source to share
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.
source to share