http://www.perlmonks.org?node_id=801848


in reply to string in system command

Don't forget that you need to protect some special characters from shell interpretation in the general case when you cannot guarantee your file naming at exactly 100%. This includes files created by nice little programming or commandline errors starting with simple oversights such as a command creating "-" instead of understanding it as the intended /dev/stdout alias within a pipe.

The special characters to protect include quotes, dollar signs or whitespace and semicolons. Just placing double quotes around a string only takes care of whitespace, semicolons and single quotes.

$file='a" b ; echo "$c '; $output=`cp "$file" newfile 2>&1`; # will fail despite of double-quote quoting

You can of course, ignore this issue. Which is safe to do, IFF you have 100% control of your filenames and know that they contain spaces at worst: You trust all your code, all the code is error-free, there's no bitrot in DRAM or disk, etc. pp. But in reality none of these preconditions is valid, so we better have quality & well-tested backups. Or we just use ...

Some reasonably safe work-arounds on Unix (and most of cygwin) are, in my subjective order of preference:

  1. place the files in shell variables using %ENV:
    ($ENV{f1},$ENV{f2})=("$DIR/$FILE", "$DIR2/${FILE}_devl"); $output=`cp "\$f1" "\$f2" 2>&1`;
  2. use the list form of exec/system to run the command directly without going through the shell:
    system("cp","$DIR/$FILE", "$DIR2/${FILE}_devl").

    For `` aka qx!!, use the 4+ argument form of open(FH,"-|","cmd","arg1",...).

  3. if unavoidable: quote or escape offending characters for use in either bare-word, single or double quoted shell string.

    First check cpan, as there might be an os- and shell-agnnostic module for this. If you need to do it yourself, consider e.g.
    s/["`\\\$]/\\$&/g (escaping for double quotes) or
    s/'/'"'"'/g (shell string concatenation for single quotes; this is more or less what the String::ShellQuote does, just w/o adding single-quotes around the string. Another example module using such regexes ARGV::readonly for treating the secure filename issue when using the magic-and-intentionally--broken <> - both of which work on Unix/Bourne-Shell, and both of which do not seem to be very OS-agnostic to me).

Notes:

Related issues to keep in mind:

Some of the App:: or Logging:: modules & frameworks might offer some support for these concerns as well. If so: Which of these do you trust and suggest for both security as well as cutting down on boilerplate code?

cu
Peter