How can I avoid an arbitrary string to use as a command line argument in Windows?

I have a list of strings and I want to pass these strings as arguments in a single Windows command line call. For simple alphanumeric strings, just pass them verbatim:

> script.pl foo bar baz yes no foo bar baz yes no 

I understand that if an argument contains spaces or double quotes, I need a backslash - avoid double quotes and backslashes, and then specify the argument twice.

 > script.pl foo bar baz "\"yes\"\\\"no\"" foo bar baz "yes"\"no" 

But when I try to pass an argument with literal percent signs, this happens:

 > script.pl %PATH% C:\Program Files\PHP\;C:\spaceless\perl\bin\;C:\Program Files\IBM\Java60\bin; (...etc.) 

Double quoting does not work:

 > script.pl "%PATH%" C:\Program Files\PHP\;C:\spaceless\perl\bin\;C:\Program Files\IBM\Java60\bin; (...etc.) 

The backslash does not work (note how the backslash is present in the output):

 > script.pl \%PATH\% \%PATH\% 

In addition, the rules are not compatible for backslashes with backslashes:

 > script.pl "\\yes\\" \\yes\ > script.pl "\yes\\" \yes\ > script.pl "\yes\" \yes" 

In addition, there are special characters on the Windows command line command line, as in all shells. What is the general procedure for safely escaping arbitrary command line arguments for use on a Windows command line?

The ideal answer will describe the escape() function, which can be used in the following situations (Perl example):

 $cmd = join " ", map { escape($_); } @args; 

Here are some examples of strings that should be safely escaped by this function (I know some of them look like Unix-like, intentional):

 yes no child.exe argument 1 Hello, world Hello"world \some\path with\spaces C:\Program Files\ she said, "you had me at hello" argument"2 \some\directory with\spaces\ " \ \\ \\\ \\\\ \\\\\ "\ "\T "\\T !1 !A "!\/'" "Jeff's!" $PATH %PATH% & <>|&^ ()%!^"<>&| >\\.\nul malicious argument"&whoami *@ $$A$@ #?-_ 
+6
source share
2 answers

Here is the blogdost msdn blog showing how to do this. However, it assumes that every command-line program internally uses CommandLineToArgvW to parse this command line (not a shaky assumption, as it is part of the Shell32 library).

http://blogs.msdn.com/b/twistylittlepassagesallalike/archive/2011/04/23/everyone-quotes-arguments-the-wrong-way.aspx

+3
source

To avoid the command line argument, use the following:

 sub escapeArg { my $arg = shift; # Sequence of backslashes followed by a double quote: # double up all the backslashes and escape the double quote $arg =~ s/(\\*)"/$1$1\\"/g; # Sequence of backslashes followed by the end of the arg, # which will become a double quote later: # double up all the backslashes $arg =~ s/(\\*)$/$1$1/; # All other backslashes do not need modifying # Double-quote the whole thing $arg = "\"".$arg."\""; # Escape shell metacharacters $arg =~ s/([()%!^"<>&|;, ])/\^$1/g; return $arg; } 

To avoid the actual command line command, for example, when invoking a command with an absurd name, for example ()!&%PATH%^;, .exe (which is completely legal), use the following:

 sub escapeCmd { my $arg = shift; # Escape shell metacharacters $arg =~ s/([()%!^"<>&|;, ])/\^$1/g; return $arg; } 

Note that using the escapeArg() command for the command will not work.

Sources:

+4
source

Source: https://habr.com/ru/post/891026/


All Articles