什么是`cmd / s`?

Windows命令提示符cmd.exe )有一个可选的/s参数 ,它修改/c (运行特定命令,然后退出)或/k (运行特定命令,然后显示shell提示符)的行为。 这个参数显然与一些神秘的报价处理有关。

这些文档是令人困惑的,但据我所知,当你做cmd /c something ,而something包含引号时,默认情况下, cmd有时会去掉这些引号,并且/s告诉它离开它们。

我不明白的是,删除报价会破坏任何东西,因为这是唯一的时间/s (“压制默认报价 – 删除行为”)将是必要的。 它只能删除某些奥术条件下的引号,其中一个条件是/c后面的第一个字符必须是引号。 所以这不是删除引号的引号; 它要么删除你正在运行的EXE的path,要么绕着整个命令行(或者可能在命令行的前半部分,这将是奇怪的)周围的引号。

  • 如果EXE的path被引用,例如cmd /c "c:\tools\foo.exe" arg1 arg2 ,那么引号是不必要的,如果cmd想要删除它们,那就好了。 (如果path名称中有一个空格,这将不会删除它们 – 这是另一个神秘的规则。)我无法想象任何理由压制报价移除,所以/s似乎没有必要。
  • 如果整个命令行被引用,例如cmd /c "foo.exe arg1 arg2" ,那么看起来像引用删除将是必要的,因为系统上没有名为foo.exe arg1 arg2 EXE; 所以它似乎select退出报价删除使用/s会实际上破坏的东西。 (但实际上,它并没有破坏: cmd /s /c "foo.exe arg1 arg2"工作正常。)

有没有一些微妙的东西可以避开我? 什么时候有必要? 什么时候甚至会有所作为?

Cmd / S是非常有用的,因为它可以节省您不必担心“引用引号”。 回想一下, /C参数的意思是“执行这个命令,就好像我在提示符下键入了它,然后退出”。

所以,如果你有一个复杂的命令,你要传递给CMD.exe,你必须记住CMD的参数引用规则,并正确地转义所有的引号,或者使用/S ,这会触发一个特殊的不解析规则“Strip第一个和最后一个" ,并将所有其他字符视为执行不变的命令”。

您可以在需要利用CMD shell功能的地方使用它,而不是直接调用另一个程序。 例如环境变量扩展,输出或输入重定向,或使用CMD.exe内置程序。

例:

使用内置的shell:如果在提示符下键入了DEL /Q/S "%TMP%\TestFile"

 CMD.exe /S /C " DEL /Q/S "%TMP%\TestFile" " 

这将执行SomeCommand.exe将标准输出重定向到临时文件并将标准错误重定向到相同的位置:

 CMD.exe /S /C " "%UserProfile%\SomeCommand.exe" > "%TMP%\TestOutput.txt" 2>&1 " 

那么/S给你什么额外的? 主要它可以节省您不必担心引用报价。 这也有助于你不确定例如一个环境变量是否包含引号字符。 只要说/S并在开始和结束时加上一个额外的报价。

隐约地相关:Bourne Shell中的$ *。

一些背景

回想一下main()的参数列表是一个C-ism和Unix-ism。 Unix / Linux shell(例如Bourne Shell等)解释命令行,取消引用参数,扩展通配符(如*到文件列表),并将参数列表传递到被调用的程序。

所以如果你说:

 $ vi *.txt 

vi命令可以看到这些参数:

 vi a.txt b.txt c.txt d.txt 

这是因为unix / linux在“参数列表”的基础上内部运行。

最终从CP / M和VAX派生的Windows不在内部使用该系统。 对于操作系统来说,命令行只是一个字符串。 被调用程序的职责是解释命令行,扩展文件( * etc)和处理引用的引用参数。

所以C期望的参数必须被C运行时库破解。 操作系统只提供一个带有参数的单个字符串,如果你的语言不是C(即使是这样),它可能不会被解释为根据shell规则引用的空格分隔的参数,而是完全不同的东西。

这里有一个例子,它可以如何有所作为。

假设您有两个可执行文件: c:\Program.exec:\Program Files\foo.exe

如果你说

 cmd /c "c:\Program Files\foo" 

你会运行foo.exe (没有参数),而如果你说

 cmd /s /c "c:\Program Files\foo" 

您将以Files\foo作为参数运行Program.exe

(奇怪的是,在第一个例子中,如果foo.exe不存在, Program.exe将会运行。)

附录:如果你打字

  c:\Program Files\foo 

在命令提示符下,您将运行Program.exe (与cmd / s / c一样),而不是运行foo.exe (就像cmd / c一样)。 所以使用/ s的一个原因是,如果你想确保一个命令的解析方式与在命令提示符下键入的方式完全一样。 在Michael Burr所关联的问题的场景中,这可能更有可能,cmd.exe由CreateProcess启动,而不是从批处理文件或命令行本身启动。

也就是说,如果你说

 CreateProcess("cmd.exe", "cmd /s /c \"" MY_COMMAND "\"", ...) 

那么字符串MY_COMMAND将被解析,就像在命令提示符下输入一样。 如果您正在从用户那里获取命令行输入,或者您是一个处理应用程序提供的命令行的库,那么这可能是一个好主意。 例如,C运行时库system()函数可能以这种方式实现。