Windows "cmd.exe" 是否以不同方式解析参数?
Does the Windows "cmd.exe" parse arguments differently?
在我看来,Windows cmd.exe
解析参数字符串的方式与 C 编译的 exe 的解析方式不同。
为了说明,cmd /C "echo ok"
正确打印了 "ok"。但是,cmd "/C" "echo ok"
结果是
'"echo ok' is not recognized as an internal or external command,
operable program or batch file.
为了比较,这是一个 C 程序 "CommandArguments.c",它逐行打印参数:
int main(int argc, char *argv[])
{
int i;
for (i = 0; i < argc; ++i) {
printf("%s\n", argv[i]);
}
}
如果我运行 CommandArguments.exe "/C" "echo ok"
,它会正确打印
CommandArguments.exe
/C
echo ok
我问这个是因为我正在实施 API 来包装 CreateProcess
。在传递给 CreateProcess
之前,我引用并转义了所有输入参数。由于上述问题,它适用于大多数情况,但不适用于 cmd
。
所以,我想知道为什么 cmd
的行为不同?它的参数解析规则是什么?有没有其他程序也以不同的方式解析参数?
有趣的观察! cmd.exe
真的很不一样!查看 cmd.exe /?
的文档会发现以下内容:
If you specify /c or /k, cmd processes the remainder of string and quotation marks are preserved
通过试验我发现 /C
选项会从 window!
中抛出正常的命令行处理
C:\Users\Lukas>cmd "/C" "ECHO Hallo"
'"echo ok' is not recognized as an internal or external command,
operable program or batch file.
C:\Users\Lukas>cmd /CECHO Hallo
Hallo
C:\Users\Lukas>cmd "/CECHO Hallo"
Hallo"
C:\Users\Lukas>
我的猜测是 cmd.exe
在命令行中找到 /C
后停止使用正常的命令行处理,并简单地将剩余的字符串传递给命令处理器(如文档中所述) ).如果这是真的,除了在包装器中以不同方式处理 cmd.exe
的(丑陋的)变通方法之外,没有解决您的问题的方法。
任何应用程序都可以以任何它认为合适的方式解析命令行。大多数应用程序使用 C 运行time 库解析器,但没有要求这样做。
理想情况下,您的 API 应该要求调用者为命令行提供单个字符串而不是参数数组,因为这是启动 Windows 进程的正确语法。
如果这不可行,您至少应该为调用者提供一个选项,以防目标应用程序需要特殊处理。
至于命令处理器,其解析行为记录在内置帮助中 (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:
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.
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.
这有点乱,但您可以通过提供 /S 开关来简化它。如果你想要 运行 的命令是 [foo]
那么只需使用
cmd /s /c "[foo]"
正如其他答案已经指出的那样,cmd
在遇到 /C
或 /K
开关时停止解析参数,并将整个剩余字符串传递给命令处理器。
为什么?因为 /C
//K
之后的字符串被认为是另一个完整的命令行,所以参数 not 属于 cmd
.
例如,我们有这样一个命令行:
cmd /S /C del /Q "any file.txt"
所以 /S
和 /C
都是 cmd
的参数,但是 del
、/Q
... 不是。 /C
之后的所有内容都放在一起并作为单独的命令行处理:
del /Q "any file.txt"
参数/Q
和"any file.txt"
属于命令del
。
在我看来,Windows cmd.exe
解析参数字符串的方式与 C 编译的 exe 的解析方式不同。
为了说明,cmd /C "echo ok"
正确打印了 "ok"。但是,cmd "/C" "echo ok"
结果是
'"echo ok' is not recognized as an internal or external command,
operable program or batch file.
为了比较,这是一个 C 程序 "CommandArguments.c",它逐行打印参数:
int main(int argc, char *argv[])
{
int i;
for (i = 0; i < argc; ++i) {
printf("%s\n", argv[i]);
}
}
如果我运行 CommandArguments.exe "/C" "echo ok"
,它会正确打印
CommandArguments.exe
/C
echo ok
我问这个是因为我正在实施 API 来包装 CreateProcess
。在传递给 CreateProcess
之前,我引用并转义了所有输入参数。由于上述问题,它适用于大多数情况,但不适用于 cmd
。
所以,我想知道为什么 cmd
的行为不同?它的参数解析规则是什么?有没有其他程序也以不同的方式解析参数?
有趣的观察! cmd.exe
真的很不一样!查看 cmd.exe /?
的文档会发现以下内容:
If you specify /c or /k, cmd processes the remainder of string and quotation marks are preserved
通过试验我发现 /C
选项会从 window!
C:\Users\Lukas>cmd "/C" "ECHO Hallo"
'"echo ok' is not recognized as an internal or external command,
operable program or batch file.
C:\Users\Lukas>cmd /CECHO Hallo
Hallo
C:\Users\Lukas>cmd "/CECHO Hallo"
Hallo"
C:\Users\Lukas>
我的猜测是 cmd.exe
在命令行中找到 /C
后停止使用正常的命令行处理,并简单地将剩余的字符串传递给命令处理器(如文档中所述) ).如果这是真的,除了在包装器中以不同方式处理 cmd.exe
的(丑陋的)变通方法之外,没有解决您的问题的方法。
任何应用程序都可以以任何它认为合适的方式解析命令行。大多数应用程序使用 C 运行time 库解析器,但没有要求这样做。
理想情况下,您的 API 应该要求调用者为命令行提供单个字符串而不是参数数组,因为这是启动 Windows 进程的正确语法。
如果这不可行,您至少应该为调用者提供一个选项,以防目标应用程序需要特殊处理。
至于命令处理器,其解析行为记录在内置帮助中 (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:
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.
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.
这有点乱,但您可以通过提供 /S 开关来简化它。如果你想要 运行 的命令是 [foo]
那么只需使用
cmd /s /c "[foo]"
正如其他答案已经指出的那样,cmd
在遇到 /C
或 /K
开关时停止解析参数,并将整个剩余字符串传递给命令处理器。
为什么?因为 /C
//K
之后的字符串被认为是另一个完整的命令行,所以参数 not 属于 cmd
.
例如,我们有这样一个命令行:
cmd /S /C del /Q "any file.txt"
所以 /S
和 /C
都是 cmd
的参数,但是 del
、/Q
... 不是。 /C
之后的所有内容都放在一起并作为单独的命令行处理:
del /Q "any file.txt"
参数/Q
和"any file.txt"
属于命令del
。