Reputation: 6127
I am trying to run the following command:
forfiles /p ..\Schemas /m *.xsd /c "cmd /c ""C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.6.1 Tools\xsd.exe @path /classes"""
However, it fails with:
ERROR: Invalid argument/option - 'Files'.
Type "FORFILES /?" for usage.
These also don't work:
forfiles /p ..\Schemas /m *.xsd /c "cmd /c \"C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.6.1 Tools\xsd.exe\" @path /classes"
forfiles /p ..\Schemas /m *.xsd /c "cmd /c ^"C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.6.1 Tools\xsd.exe^" @path /classes"
It's definitely failing because the path being passed to cmd
contains spaces. You normally solve this by quoting the whole argument. However, there doesn't appear to be a way to pass the double quote.
So, how do you run a command with a full path from the Windows forfiles command?
Upvotes: 3
Views: 18904
Reputation: 34919
In your first attempt, you tried to put (additional) quotation marks around the entire command line after cmd /c
rather than the path to the executable only, which will fail as cmd
tries to find and execute the whole line as a command. Hence you needed to move the closing quotes immediately after xsd.exe
instead of at the end of the command line.
Nevertheless, in general, the main problem here is that cmd
and forfiles
handle quotation marks differently. forfiles
uses \"
to escape quoting, but cmd
does not care about the backslash. In addition, in case your code appears within a parenthesised block of code, the literal parentheses in your path may cause trouble additionally if they do not appear quoted to cmd
. Finally, cmd
may attempt to strip off quotation marks (unexpectedly), which may cause even more problems.
To solve all this, use another method of providing literal quotation marks for the command line after /C
: forfiles
supports specifying characters by their hexadecimal code in 0xHH
notation; so stating 0x22
hides the quotation marks from the parent cmd
instance until the command line is actually executed:
forfiles /p ..\Schemas /m *.xsd /c "cmd /c 0x220x22C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.6.1 Tools\xsd.exe0x22 @path /classes0x22"
This results in the following command line to be executed (using "D:\Data\Schemas\sample.xsd"
as an example value for @path
):
cmd /c ""C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.6.1 Tools\xsd.exe" "D:\Data\Schemas\sample.xsd" /classes"
Finally, after stripping off the outer-most quotes by cmd
, the following command line is executed:
"C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.6.1 Tools\xsd.exe" "D:\Data\Schemas\sample.xsd" /classes
Note that @path
, as well as all other file-name- and path-related @
-style variables of forfiles
expand to already quoted values.
Initially, I completely forgot about the fact that cmd
tries to strip off quotes. Klitos Kyriacou's answer reminded me of that; so if you like my answer, please do not forget to give credits to them as well!
Upvotes: 4
Reputation: 11631
It's not forfiles
that's at fault here; it's the way cmd.exe treats quotation marks. It's essentially trying to be too clever for its own good. The CMD /C
command can take any arbitrary line as a command, including one that contains spaces; however, if the command line given after CMD /C
starts with a quotation mark, it removes the first and last quotation marks from the line before it tries to execute it. Thus, these two lines are exactly equivalent:
cmd /c echo hello
cmd /c "echo hello"
Now the problem is that the quotation mark gets stripped off in the following command:
cmd /c "C:\Program Files\xyz\abc.exe" one two
To make it do what you want, you need to enclose the whole thing in quotes (the inner quotes don't need to be escaped):
cmd /c ""C:\Program Files\xyz\abc.exe" one two"
Now, you can put this into a FORFILES
command. FORFILES requires quotation marks to be escaped with a \
, so we need to write:
forfiles /c "cmd /c \"\"C:\Program Files\xyz\abc.exe\" one two\""
Or in your specific case:
forfiles /p ..\Schemas /m *.xsd /c "cmd /c \"\"C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.6.1 Tools\xsd.exe\" @path /classes\""
(Note that all quotation marks for CMD
are escaped, but the outer quotation marks are for FORFILES
so are not escaped.)
Upvotes: 3