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

前端 未结 2 1457
温柔的废话
温柔的废话 2021-01-29 08:38

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\" )\         


        
2条回答
  •  离开以前
    2021-01-29 09:02

    system has three calling conventions:

    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)
    

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

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

    echo \* | cat -n
    

    or

    echo '*' | cat -n
    

    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 <>
         1  *
    

    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.

提交回复
热议问题