149

In Unix I could run myscript '"test"' and I would get "test".

In Windows cmd I get 'test'.

How can I pass double-quotes as a parameter? I would like to know how to do this manually from a cmd window so I don't have to write a program to test my program.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
700 Software
  • 85,281
  • 83
  • 234
  • 341
  • 3
    It has been years since I have touched a windows machine, but doesn't the standard escape character (backslash \ ) work? e.g. `myscript \"test\"` – Gazler Oct 13 '11 at 21:19
  • Nope. I get \test\. I suspect that is because windows uses \ instead of / so backslash cannot be used as an escaper. But I don't really know. – 700 Software Oct 13 '11 at 21:21
  • 1
    Idk what version of Windows you're using, but \" works fine on Windows 7 (Ultimate). There's another way to do it though, dealing with multiple quotes (i.e. """ becomes " or something), but I can't figure out when and how it works. – Codesmith Mar 07 '13 at 00:28
  • 3
    possible duplicate of [Escaping Double Quotes in Batch Script](http://stackoverflow.com/questions/562038/escaping-double-quotes-in-batch-script) – sirdank May 04 '15 at 20:30

6 Answers6

236

Another way to escape quotes (though probably not preferable), which I've found used in certain places is to use multiple double-quotes. For the purpose of making other people's code legible, I'll explain.

Here's a set of basic rules:

  1. When not wrapped in double-quoted groups, spaces separate parameters:
    program param1 param2 param 3 will pass four parameters to program.exe:
         param1, param2, param, and 3.
  2. A double-quoted group ignores spaces as value separators when passing parameters to programs:
    program one two "three and more" will pass three parameters to program.exe:
         one, two, and three and more.
  3. Now to explain some of the confusion:
  4. Double-quoted groups that appear directly adjacent to text not wrapped with double-quotes join into one parameter:
    hello"to the entire"world acts as one parameter: helloto the entireworld.
  5. Note: The previous rule does NOT imply that two double-quoted groups can appear directly adjacent to one another.
  6. Any double-quote directly following a closing quote is treated as (or as part of) plain unwrapped text that is adjacent to the double-quoted group, but only one double-quote:
    "Tim says, ""Hi!""" will act as one parameter: Tim says, "Hi!"

Thus there are three different types of double-quotes: quotes that open, quotes that close, and quotes that act as plain-text.
Here's the breakdown of that last confusing line:

"   open double-quote group
T   inside ""s
i   inside ""s
m   inside ""s
    inside ""s - space doesn't separate
s   inside ""s
a   inside ""s
y   inside ""s
s   inside ""s
,   inside ""s
    inside ""s - space doesn't separate
"   close double-quoted group
"   quote directly follows closer - acts as plain unwrapped text: "
H   outside ""s - gets joined to previous adjacent group
i   outside ""s - ...
!   outside ""s - ...
"   open double-quote group
"   close double-quote group
"   quote directly follows closer - acts as plain unwrapped text: "

Thus, the text effectively joins four groups of characters (one with nothing, however):
Tim says,  is the first, wrapped to escape the spaces
"Hi! is the second, not wrapped (there are no spaces)
 is the third, a double-quote group wrapping nothing
" is the fourth, the unwrapped close quote.

As you can see, the double-quote group wrapping nothing is still necessary since, without it, the following double-quote would open up a double-quoted group instead of acting as plain-text.

From this, it should be recognizable that therefore, inside and outside quotes, three double-quotes act as a plain-text unescaped double-quote:

"Tim said to him, """What's been happening lately?""""

will print Tim said to him, "What's been happening lately?" as expected. Therefore, three quotes can always be reliably used as an escape.
However, in understanding it, you may note that the four quotes at the end can be reduced to a mere two since it technically is adding another unnecessary empty double-quoted group.

Here are a few examples to close it off:

program a b                       REM sends (a) and (b)
program """a"""                   REM sends ("a")
program """a b"""                 REM sends ("a) and (b")
program """"Hello,""" Mike said." REM sends ("Hello," Mike said.)
program ""a""b""c""d""            REM sends (abcd) since the "" groups wrap nothing
program "hello to """quotes""     REM sends (hello to "quotes")
program """"hello world""         REM sends ("hello world")
program """hello" world""         REM sends ("hello world")
program """hello "world""         REM sends ("hello) and (world")
program "hello ""world"""         REM sends (hello "world")
program "hello """world""         REM sends (hello "world")

Final note: I did not read any of this from any tutorial - I came up with all of it by experimenting. Therefore, my explanation may not be true internally. Nonetheless all the examples above evaluate as given, thus validating (but not proving) my theory.

I tested this on Windows 7, 64bit using only *.exe calls with parameter passing (not *.bat, but I would suppose it works the same).

Codesmith
  • 5,779
  • 5
  • 38
  • 50
  • 14
    +1, but note that this behavior depends on the application. In Windows, each application parses its own command line parameters. I believe the behavior you're describing is that of Microsoft's standard C library, which I think is also duplicated by most other Windows C compilers. – Harry Johnston Oct 02 '13 at 03:49
  • 1
    Nice explanation and breakdown! I can finally understand the """"quote interpretation"" :] – mousio Mar 28 '14 at 14:58
  • 3
    Multiple errors in your last exepriment. program """a b""" -> ("a b"), program "hello to """quotes"" -> (hello to "quotes), program """"hello world"" -> ("Hello)(world), program """hello" world"" -> ("hello)(world), program """hello "world"" ->("hello world), program "hello """world"" -> (hello "world) – Thomson Nov 27 '14 at 07:13
  • 60
    ...All I can say is, Windows batch files have problems. This is *escaping quotes*, for Christ's sake; it shouldn't have to be some kind of rocket science. – James Ko Dec 13 '15 at 18:28
  • 8
    @JamesKo I couldn't agree more. The arcane absurdity and inconsistency of the Windows command line never fails to anger me. Who designed this junk? Oh, the hours wasted over the years! Unix is so easy and makes so much sense in comparison. – Carlos A. Ibarra May 25 '17 at 19:28
  • If you want a single quote to appear in a string, the parameter must close with a double quote. E.g. "ABC""DEF"" will pass a single parameter of ABC"DEF – Paul Dolphin Jan 24 '18 at 11:20
  • 12
    For an in-depth explanation, see *[How Command Line Parameters Are Parsed](http://daviddeley.com/autohotkey/parameters/parameters.htm)* and *[A Better Way To Understand Quoting and Escaping of Windows Command Line Arguments](http://www.windowsinspired.com/understanding-the-command-line-string-and-arguments-received-by-a-windows-program/)*. – Peter Mortensen Sep 11 '18 at 20:09
  • This is not necessarily true, and the correct answer depends on which program is called. Refer to https://stackoverflow.com/a/31413730/5267751. – user202729 Jan 24 '23 at 04:41
31

I cannot quickly reproduce the symptoms: if I try myscript '"test"' with a batch file myscript.bat containing just @echo.%1 or even @echo.%~1, I get all quotes: '"test"'

Perhaps you can try the escape character ^ like this: myscript '^"test^"'?

mousio
  • 10,079
  • 4
  • 34
  • 43
  • 1
    To reproduce, you can create a file `test.js` that contains `WScript.Echo(WScript.Arguments(0))` and open `cmd` and type `wscript test.js '^"test^"'`. You will find that both the carrot and double-quotes get stripped. – 700 Software Oct 13 '11 at 21:30
  • 3
    Then maybe the answers to [this question](http://stackoverflow.com/q/4192376/653295) might help you further? – mousio Oct 13 '11 at 21:38
  • 2
    Ha! I never would have guessed it was `wscript`'s fault! Leave it to Windows :) – 700 Software Oct 13 '11 at 21:41
  • 6
    Actually ^ didn't work for me, but \ did, per this answer: http://stackoverflow.com/questions/2403647/how-to-escape-parameter-in-windows-command-line – kalenjordan Aug 16 '12 at 22:05
  • 39
    Windows: the OS where globbing, shell expansion, and parameter unescaping is performed by the executable being invoked instead of the shell. You never know which convention, if any, the invoked executable honours. – binki Mar 28 '14 at 02:15
  • 1
    For me, enclosing the parameter in single quotes e.g. `'^"test^"'` didn't work, but without single quotes, e.g. `^"test^"` _did_ work, on Windows 7. I have no idea why. Side note: I've found that to escape double-quotes within a string (or double-quotes within double-quotes), the outer quotes must be escaped. – Alex Hall Jan 17 '16 at 06:19
  • 9
    Valuable input: https://blogs.msdn.microsoft.com/twistylittlepassagesallalike/2011/04/23/everyone-quotes-command-line-arguments-the-wrong-way/. The caret is indeed the escape character of choice for `cmd`. – Peter - Reinstate Monica May 09 '18 at 10:01
  • _Very_ valuable input, indeed! (at least for those still relying on cmd) Thank you, @peter! – mousio May 09 '18 at 16:14
  • 1
    @mousio Thanks. I was about to write a suggestion for the OP and then realized that even after reading that article a couple of times I *still* wasn't sure how to do it correctly. That's terrible because I"ll not be the only one. Then I had an epiphany, at least for my use case: Execute a `bat` command in a groovy Jenkins script which calls git bash with arguments that may contain literal quotes. We have groovy string syntax (escape quotes and backslashes with backslashes), then `cmd` parsing, then Windows argument processing, then bash argument processing. (t.b.c.) – Peter - Reinstate Monica May 09 '18 at 16:31
  • @mousio ... Solution: Write commands to a temporary file (so that string literals only undergo groovy parsing which is by itself understandable) and pass the file path as the only argument to the bash invocation via `bat`. Then none of the actual bash commands are touched by either `cmd` or `CommandLineToArgvW`, and multi-line-ability is added as a bonus. – Peter - Reinstate Monica May 09 '18 at 16:35
28

Try this:

myscript """test"""

"" escape to a single " in the parameter.

smwikipedia
  • 61,609
  • 92
  • 309
  • 482
  • 5
    That's not quite correct. Try `myscript """test test"""` and it doesn't work (first parameter is handed over as `"test`. Acutally, you need three quotes: `myscript """"test test""` The third quote at the end can be skipped, though. – Ignitor Jun 24 '15 at 14:45
  • what if I need to remove all the quotes here and place the parameter value in a string used in a select query filter? Can someone help? – SFDC_Learner Nov 24 '15 at 16:21
  • 2
    Maybe not spot on for this question, but this helped me when I needed to pass `char **argv` from my C launcher to another process using functions like `spawn` or `exec`. Thank you. :-) – virgo47 Dec 15 '15 at 08:26
9

The 2nd document quoted by Peter Mortensen in his comment on the answer of Codesmith made things much clearer for me. That document was written by windowsinspired.com. The link repeated: A Better Way To Understand Quoting and Escaping of Windows Command Line Arguments.

Some further trial and error leads to the following guideline:

Escape every double quote " with a caret ^. If you want other characters with special meaning to the Windows command shell (e.g., <, >, |, &) to be interpreted as regular characters instead, then escape them with a caret, too.

If you want your program foo to receive the command line text "a\"b c" > d and redirect its output to file out.txt, then start your program as follows from the Windows command shell:

foo ^"a\^"b c^" ^> d > out.txt

If foo interprets \" as a literal double quote and expects unescaped double quotes to delimit arguments that include whitespace, then foo interprets the command as specifying one argument a"b c, one argument >, and one argument d.

If instead foo interprets a doubled double quote "" as a literal double quote, then start your program as

foo ^"a^"^"b c^" ^> d > out.txt

The key insight from the quoted document is that, to the Windows command shell, an unescaped double quote triggers switching between two possible states.

Some further trial and error implies that in the initial state, redirection (to a file or pipe) is recognized and a caret ^ escapes a double quote and the caret is removed from the input. In the other state, redirection is not recognized and a caret does not escape a double quote and isn't removed. Let's refer to these states as 'outside' and 'inside', respectively.

If you want to redirect the output of your command, then the command shell must be in the outside state when it reaches the redirection, so there must be an even number of unescaped (by caret) double quotes preceding the redirection. foo "a\"b " > out.txt won't work -- the command shell passes the entire "a\"b " > out.txt to foo as its combined command line arguments, instead of passing only "a\"b " and redirecting the output to out.txt.

foo "a\^"b " > out.txt won't work, either, because the caret ^ is encountered in the inside state where it is an ordinary character and not an escape character, so "a\^"b " > out.txt gets passed to foo.

The only way that (hopefully) always works is to keep the command shell always in the outside state, because then redirection works.

If you don't need redirection (or other characters with special meaning to the command shell), then you can do without the carets. If foo interprets \" as a literal double quote, then you can call it as

foo "a\"b c"

Then foo receives "a\"b c" as its combined arguments text and can interpret it as a single argument equal to a"b c.

Now -- finally -- to the original question. myscript '"test"' called from the Windows command shell passes '"test"' to myscript. Apparently myscript interprets the single and double quotes as argument delimiters and removes them. You need to figure out what myscript accepts as a literal double quote and then specify that in your command, using ^ to escape any characters that have special meaning to the Windows command shell. Given that myscript is also available on Unix, perhaps \" does the trick. Try

myscript \^"test\^"

or, if you don't need redirection,

myscript \"test\"
beatcracker
  • 6,714
  • 1
  • 18
  • 41
Louis Strous
  • 942
  • 9
  • 15
  • THANK YOU! I was beating my head on the wall trying to run a vbscript with cmd prompt text being echoed into cmd prompt text - I inherited this - and could not figure out a way to escape the quotes. – PopeDarren Oct 24 '19 at 21:26
  • I came here indirectly, but it turns out CreateProcessExW also needs quotes to be escaped by ^. Iow it is not entirely shell only. – Marco van de Voort Apr 15 '21 at 14:57
  • I wanted to set a value for a `git` configuration setting; I tried following the instructions here and couldn't get it to work. I wanted `git config --global --list` to give me something like this: `difftool.winmerge.cmd=winmerge.BAT "%%LOCAL%%" "%%REMOTE%%"` To do that, I had to have the following line in my BAT file: `git config --replace --global difftool.winmerge.cmd "winmerge.BAT "^""%%LOCAL%%"^"" "^""%%REMOTE%%"^"` Does that fit the inside/outside model? – rich p Aug 08 '23 at 21:03
3

I'm calling powershell from cmd, and passing quotes and neither escapes here worked. The grave accent worked to escape double quotes on this Win 10 surface pro.

>powershell.exe "echo la`"" >> test
>type test
la"

Below are outputs I got for other characters to escape a double quote:

la\
la^
la
la~

Using another quote to escape a quote resulted in no quotes. As you can see, the characters themselves got typed, but didn't escape the double quotes.

Zimba
  • 2,854
  • 18
  • 26
2

Maybe you came here, because you wonder how to escape quotes that you need in the command that you pass to /c on cmd.exe? Well you don't:

CMD /c "MKDIR "foo bar""

will execute

MKDIR "foo bar"

which is really a behavior that I did not expect in the first glance.

Martin Braun
  • 10,906
  • 9
  • 64
  • 105