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?
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!