简体   繁体   中英

weird handling of double quotes when using cmd /c “echo”

I'm trying to escape some calls in bat file and I found out that I don't understand even on simple example the weird handling of double quotes:

Try

cmd /c "echo " "%TEMP%"                   rem this gives: " "C:\Users\xyz\AppData\Local\Temp
cmd /c "echo" "%TEMP%"                    rem this gives: The filename, directory name, or volume label syntax is incorrect.
cmd /c "echo beg "TEMP" %TEMP%"           rem this gives: beg "TEMP" C:\Users\xyz\AppData\Local\Temp
cmd /c "echo beg ^"TEMP^" %TEMP%"         rem this gives: beg "TEMP" C:\Users\xyz\AppData\Local\Temp
cmd /c "echo beg \"TEMP\" %TEMP%"         rem this gives: beg \"TEMP\" C:\Users\xyz\AppData\Local\Temp

Just open command prompt (cmd.exe) and paste code. The results are the same when copy/paste to cmd.exe or running a bat file.

What I would expect is that cmd /c "echo beg \"TEMP\" %TEMP%" should work correcctly. At least according to http://daviddeley.com/autohotkey/parameters/parameters.htm#WIN .

But I don't understand output from all the samples. Anybody could explain me that behaviour?


Edit :

The site I'm referencing just explains how arguments are parsed on Windows. Eg http://daviddeley.com/autohotkey/parameters/parameters.htm#WINCRULES

What is my expected output? I just want to know how that passing of double quotes work. Later I'd like to construct command lines like this one:

pwsh -noprofile -command "produceSomeStringsToFind | % { rg -g testfile* \" $_ some string that ends with quote\\\"" . }"

where rg is https://github.com/BurntSushi/ripgrep - where the \" $_ some string that ends with quote\\\"" part is regular expression where I need to escape the quotes.

From the help text of cmd /?:

 [...] If /C or /K is specified, then the remainder of the command line after the switch is processed as a command line, where the following logic is used to process quote (") characters: 1. If all of the following conditions are met, then quote characters on the command line are preserved: - no /S switch - exactly two quote characters - no special characters between the two quote characters, where special is one of: &<>()@^| - there are one or more whitespace characters between the two quote characters - the string between the two quote characters is the name of an executable file. 2. Otherwise, old behavior is to see if the first character is a quote character and if so, strip the leading character and remove the last quote character on the command line, preserving any text after the last quote character. [...]

It becomes clear that you are facing the situation explained in section 2. , because echo is not an executable file but an internal command. So if the first character is a " , it becomes removed and so becomes the last " , and all the other characters are preserved.


Now let us go through your command lines. So after being parsed and processed by cmd /c :

  1. cmd /c "echo " "%TEMP%" becomes echo " "C:\Users\xyz\AppData\Local\Temp .
  2. cmd /c "echo" "%TEMP%" becomes echo" "C:\Users\xyz\AppData\Local\Temp ; then the command echo" is tried to be executed, but which is not a valid one, hence it fails.
  3. cmd /c "echo beg "TEMP" %TEMP%" becomes echo beg "TEMP" C:\Users\xyz\AppData\Local\Temp .
  4. cmd /c "echo beg ^"TEMP^" %TEMP%" becomes echo beg "TEMP" C:\Users\xyz\AppData\Local\Temp , because escaping with ^ happens even before cmd /c is executed, so it receives the already escaped literal " characters.
  5. cmd /c "echo beg \"TEMP\" %TEMP%" becomes echo beg \"TEMP\" C:\Users\xyz\AppData\Local\Temp , because the \ is nothing special to cmd .

If you want to output the text "%TEMP%" (including the quotes), yo could do this:

rem // This preserves all quotes, because the first character is not such:
cmd /c echo "%TEMP%"
rem // This removes the outer-most pair of quotes, because the first character is such:
cmd /c "echo "%TEMP%""
rem /* This removes the outer-most pair of quotes too, since `cmd /c` receives the already
rem    escaped `"`; however, this could be useful to hide these quotes from the hosting
rem    `cmd` instance, which avoids issues when `%TEMP%` contains special characters
rem    (like `&` or `^`), which you would otherwise have to individually escape: */
cmd /c ^"echo "%TEMP%"^"

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM