How do I deal with quote characters when using cmd

2019-01-05 01:54发布

I'm trying to do this:

cmd.exe /C "C:\Program Files\Somewhere\SomeProgram.exe" > "C:\temp\Folder Containing Spaces\SomeProgram.out"

However, I have problems which are down to the way cmd.exe works. If you read the help for it, it handles " characters in a special way. See the help at the end of question. So, this doesn't execute correctly... I'm guessing cmd.exe strips some quotes which makes the statement ill-formed.

I can do this successfully:

// quotes not required around folder with no spaces
cmd.exe /C "C:\Program Files\Somewhere\SomeProgram.exe" > C:\temp\FolderWithNoSpaces\SomeProgram.out

But, I really need the first one to work. Is there away around the strange quote processing that cmd.exe uses? I want it to preserve all of the quotes, but there doesn't appear to be an option to make it do that.


Help taken from output 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
      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.

2条回答
叼着烟拽天下
2楼-- · 2019-01-05 02:38

I think you'll find that your example works absolutely fine as it is.

cmd.exe /C "C:\Program Files\Somewhere\SomeProgram.exe" > "C:\temp\Folder Containing Spaces\SomeProgram.out"

I have reproduced your example here http://pastebin.com/raw.php?i=YtwQXTGN

C:\>cmd /c "c:\Program Files\my folder\my long program.exe" > "c:\temp\spaces are here\a.a"

C:\>type "c:\temp\spaces are here\a.a"
my long program.exe has run

C:\>

further example demonstrating it works with "my long program.exe", removing cmd /c, it operates fine too.

C:\>"c:\Program Files\my folder\my long program.exe" > "c:\temp\spaces are here\
a.a"

C:\>type "c:\temp\spaces are here\a.a"
my long program.exe has run

C:\>



Another example, but with replace.  replace with no parameters says "source path required"  "no files replaced"

C:\>replace > a.a
Source path required

C:\>type a.a
No files replaced

Exactly the same effect when they're in folders with spaces.

C:\>cmd /c "c:\Program Files\my folder\replace.exe" > "c:\temp\spaces are here\r.r"
Source path required

C:\>type "c:\temp\spaces are here\r.r"
No files replaced

C:\>

further demonstration with replace
without cmd /c works fine too.

C:\>"c:\Program Files\my folder\replace.exe" > "c:\temp\spaces are here\r.r"
Source path required

C:\>type "c:\temp\spaces are here\r.r"
No files replaced

C:\>

The reason why your example works fine

cmd.exe /C "C:\Program Files\Somewhere\SomeProgram.exe" > "C:\temp\Folder Containing Spaces\SomeProgram.out"

and how/why it works the way it does, is because the > is interpreted as special by the host.exe So this part cmd.exe /C "C:\Program Files\Somewhere\SomeProgram.exe" - I think - is evaluated first. i.e. cmd /c does not see the > and after.

cmd /? shows 2 cases

Case 1 and Case 2. Your example fits Case 1

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.

You can test for sure that your example fits case 1, because if you add /s (without adding any more quotes or making any change at all to your example other than adding /s), then you get a different result, because it makes your example hit case 2. So that proves that your example is definitely a case 1. And it clearly meets all the criteria of case 1. If your example were a case 2, and you added /s, then it'd make no difference.

Your answer is interesting because it shows an alternative way of getting your result, but in case 2. By adding additional outter quotes and adding /s.

But actually, when you add those additional outter quotes, then you've just made it a case 2, and adding a /s on top of that won't make a difference.

C:\>cmd /c "c:\Program Files\my folder\replace.exe"
Source path required
No files replaced

C:\>cmd /s /c "c:\Program Files\my folder\replace.exe"
'c:\Program' is not recognized as an internal or external command,
operable program or batch file.

C:\>cmd /c ""c:\Program Files\my folder\replace.exe""
Source path required
No files replaced

C:\>cmd /s /c ""c:\Program Files\my folder\replace.exe""
Source path required
No files replaced

C:\>

The example in your question worked fine

cmd.exe /C "C:\Program Files\Somewhere\SomeProgram.exe" > "C:\temp\Folder Containing Spaces\SomeProgram.out"

Your alternative (with the /S and outer quotes) you give as an answer to make the example work, works fine too

cmd.exe /S /C ""C:\Program Files\Somewhere\SomeProgram.exe" > "C:\temp\Folder Containing Spaces\SomeProgram.out""

Though your answer which is an alternative, can actually be simplified by removing the /S because it's already a case 2, so adding /s won't make any difference. So this would improve the solution given in your answer

cmd.exe /C ""C:\Program Files\Somewhere\SomeProgram.exe" > "C:\temp\Folder Containing Spaces\SomeProgram.out""

Your example which you described as a problem in your question, and your solution, produce the same good result. But one big difference I suppose, (and I am not sure how to test for it), but one difference in the way your example works, and the way the solution in your answer works, is I think in the case of your example, the hosting/invoking cmd.exe does the redirect to the file. Whereas in your solution's example, the invoked cmd.exe is passed the > by the host cmd.exe, and so the invoked cmd.exe does the redirect. Also of course, your example is a case 1, while your solution is an amendment you made (very well) to make it work in case 2.

I hope I haven't erred here, I may have. But your question and answer did help me wrap my head around how cmd and in particular cmd /c is working!

Perhaps your example was an oversimplification of your actual one, and your actual one did fail and needed your amendment. If your example case, had been a tiny bit more complex, by for example, having a parameter to the program that took quotes, then it'd fail Case 1, and you would indeed need outter quotes (/S would not change the result, so no /S would be necessary, as it'd already be a case 2 once you add those needed outer quotes). But the example you gave in your question actually seems to me to work fine.

Added - A related Q and A What is `cmd /s` for?

查看更多
SAY GOODBYE
3楼-- · 2019-01-05 02:40

Ah. doh. Think I've answered my own question.

If you use /S, and wrap the whole thing in quotes, it just removes those outer quotes.

cmd.exe /S /C " do what you like here, quotes within the outermost quotes will be preserved "
查看更多
登录 后发表回答