如何从 Windows forfiles 命令中 运行 一个带有完整路径的命令?

How do you run a command with a full path from the Windows forfiles 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"""

然而,它失败了:

ERROR: Invalid argument/option - 'Files'.
Type "FORFILES /?" for usage.

这些也不起作用:

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"

肯定是失败了,因为传递给 cmd 的路径包含空格。你通常通过引用整个论点来解决这个问题。但是,似乎没有办法传递双引号。

那么,你如何运行一个带有来自 Windows forfiles 命令的完整路径的命令?

在您的第一次尝试中,您尝试在 cmd /c 之后在整个命令行周围放置(额外的)引号,而不是仅在可执行文件的路径周围放置引号,这将失败,因为 cmd 尝试查找并执行整行作为命令。因此,您需要在 xsd.exe 之后立即移动结束引号,而不是在命令行末尾。

不过,总的来说,这里的主要问题是 cmdforfiles 处理引号的方式不同。 forfiles 使用 \" 转义引号,但 cmd 不关心反斜杠。此外,如果您的代码出现在带括号的代码块中,如果它们没有出现在 cmd 的引号中,则路径中的文字括号可能会造成额外的麻烦。最后,cmd 可能会尝试去掉引号(意外),这可能会导致更多问题。

为了解决这一切,使用另一种方法在/C之后为命令行提供文字引号:forfiles支持通过0xHH表示法中的十六进制代码指定字符;所以声明 0x22 隐藏父 cmd 实例的引号,直到实际执行命令行:

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"

这会导致执行以下命令行(使用 "D:\Data\Schemas\sample.xsd" 作为 @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"

最后,通过cmd去掉最外面的引号后,执行下面的命令行:

"C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.6.1 Tools\xsd.exe" "D:\Data\Schemas\sample.xsd" /classes

请注意 @path,以及 forfiles 的所有其他与文件名和路径相关的 @ 样式变量扩展为已引用的值。


最初,我完全忘记了 cmd 试图去掉引号这一事实。 Klitos Kyriacou's 让我想起了这一点;所以如果你喜欢我的回答,请不要忘记给他们点赞哦!

这不是 forfiles 的错;这是 cmd.exe 处理引号的方式。它本质上是为了自己的利益而试图变得太聪明。 CMD /C 命令可以将任意行作为命令,包括包含空格的行;但是,如果在 CMD /C 之后给出的命令行以引号开头,它会在尝试执行之前从该行中删除第一个和最后一个引号。因此,这两行完全等价:

cmd /c echo hello
cmd /c "echo hello"

现在的问题是引号在以下命令中被删除:

cmd /c "C:\Program Files\xyz\abc.exe" one two

为了让它做你想做的事,你需要用引号将整个东西括起来(内部引号不需要转义):

cmd /c ""C:\Program Files\xyz\abc.exe" one two"

现在,您可以将其放入 FORFILES 命令中。 FORFILES要求引号用\转义,所以我们需要这样写:

forfiles /c "cmd /c \"\"C:\Program Files\xyz\abc.exe\" one two\""

或者在您的具体情况下:

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\""

(请注意,CMD 的所有引号都已转义,但外引号用于 FORFILES,因此未转义。)