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


in reply to Re: Having to manually escape quote character in args to "system"?
in thread Having to manually escape quote character in args to "system"?

Thank you, everyone, for very enlightening answers, I've learned quite a few things from them.

Unfortunately, ShellQuote::Any::Tiny doesn't do it right:

>perl -MShellQuote::Any::Tiny=shell_quote -E "system $^X, '-E', 'say f +or @ARGV; <STDIN>', 1, shell_quote(qq(\x5c \x5c)), 2" 1 \\ \ 2

because it escapes every backslash. But only terminating one, which precedes the closing double-quote (if any), should be escaped -- as follows from "Everyone quotes command line arguments the wrong way".

Win32::ShellQuote appears to handle everything correctly.

Actually, I lived happily before this, relying only on Perl's built-in ability to double-quote arguments, which contain spaces. Until someone, in her wisdom, decided that a double-quote in the middle of template name, to be passed as argument to another script, is a good idea.

  • Comment on Re^2: Having to manually escape quote character in args to "system"?
  • Download Code

Replies are listed 'Best First'.
Re^3: Having to manually escape quote character in args to "system"?
by choroba (Cardinal) on Sep 13, 2017 at 11:57 UTC
    > Unfortunately, ShellQuote::Any::Tiny doesn't do it right:

    Bug reported.

    ($q=q:Sq=~/;[c](.)(.)/;chr(-||-|5+lengthSq)`"S|oS2"`map{chr |+ord }map{substrSq`S_+|`|}3E|-|`7**2-3:)=~y+S|`+$1,++print+eval$q,q,a,
      Weep. When you dont cross check existing solution and make a "tiny" "any" module
Re^3: Having to manually escape quote character in args to "system"?
by choroba (Cardinal) on Sep 19, 2017 at 08:59 UTC
    The bug has been fixed (see my other comment for the link). Can you check?

    ($q=q:Sq=~/;[c](.)(.)/;chr(-||-|5+lengthSq)`"S|oS2"`map{chr |+ord }map{substrSq`S_+|`|}3E|-|`7**2-3:)=~y+S|`+$1,++print+eval$q,q,a,

      Thank you for reporting a bug for me, in the first place. No, fix is not good (I notified the author). Similar test fails:

      >perl -MShellQuote::Any::Tiny=shell_quote -E "system $^X, '-E', 'say f +or @ARGV', 1, shell_quote(qq(\x5c\x5c \x5c)), 2" 1 \\\ \ 2

      According to comment in source, [we now] "escape backslash that is followed by a backslash, or the last backslash". That's not what rules 4-7 in MS guidelines say, if we 'reverse' them. 'Reverse', because they say how to parse a command line, and, of course, Perl does it OK for all test cases provided on that page:

      perl -E "system $^X, '-E', 'say for @ARGV', qq(\x22abc\x22 d e)" perl -E "system $^X, '-E', 'say for @ARGV', qq(a\x5c\x5c\x5cb d\x22e f +\x22g h)" perl -E "system $^X, '-E', 'say for @ARGV', qq(a\x5c\x5c\x5c\x22b c d) +" perl -E "system $^X, '-E', 'say for @ARGV', qq(a\x5c\x5c\x5c\x5c\x22b +c\x22 d e)"

      While we need the opposite: to escape arguments, so that when Perl #1 simply glues them together, another program (e.g. Perl #2) breaks the CL to the same arguments. Line 24

      $arg =~ s/(\\(?!.*\\)|\\(?=\\)|")/\\$1/g;

      could be replaced with

      $arg =~ s/\\(?=\\*(?:"|$))/\\\\/g; $arg =~ s/"/\\"/g;

      Then round-trip tests pass OK (though they are trivial, of course):

      perl -MShellQuote::Any::Tiny=shell_quote -E "system $^X, '-E', 'say fo +r @ARGV', map {shell_quote $_} qw(abc d e)" perl -MShellQuote::Any::Tiny=shell_quote -E "system $^X, '-E', 'say fo +r @ARGV', map {shell_quote $_} qq(a\x5c\x5c\x5cb), 'de fg', 'h'" perl -MShellQuote::Any::Tiny=shell_quote -E "system $^X, '-E', 'say fo +r @ARGV', map {shell_quote $_} qq(a\x5c\x22b), 'c', 'd'" perl -MShellQuote::Any::Tiny=shell_quote -E "system $^X, '-E', 'say fo +r @ARGV', map {shell_quote $_} qq(a\x5c\x5cb c), 'd', 'e'"

      Edit. P.S. Issue fixed (on the same day) in 0.007 version. I'm out of issues.

      :-)