在我看来,Windows cmd.exe
解析参数字符串与C编译的exe的正常程度不同。
为了说明,cmd /C "echo 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
表现不同?解析规则的论点是什么?还有其他程序还以不同的方式解析参数吗?
答案 0 :(得分:3)
任何应用程序都可以以其认为合适的任何方式解析命令行。大多数应用程序使用C运行时库解析器,但没有要求这样做。
理想情况下,您的API应该要求调用者为命令行提供单个字符串而不是参数数组,因为这是启动Windows进程的正确语法。
如果这不可行,那么在目标应用程序需要特殊处理的情况下,您应该至少为调用者提供选项。
对于命令处理器,其解析行为记录在内置帮助中(cmd /?
):
如果指定了/ C或/ K,那么后面的命令行的其余部分 交换机作为命令行处理,其中包含以下逻辑 用于处理引号(&#34;)字符:
如果满足以下所有条件,则引用字符 在命令行上保留:
- 否/ S开关
- 正好两个引号字符
- 两个引号字符之间没有特殊字符, special是以下之一:&amp;&lt;&gt;()@ ^ |
- 之间有一个或多个空格字符 两个引号字符
- 两个引号字符之间的字符串是名称 可执行文件。
- 醇>
否则,旧行为是查看第一个字符是否为 引用字符,如果是这样,剥去主角和 删除命令行上的最后一个引号字符,保留 最后一个引号字符后面的任何文字。
这有点乱,但您可以通过提供/ S开关来简化它。如果您要运行的命令是[foo]
,那么只需使用
cmd /s /c "[foo]"
答案 1 :(得分:2)
cmd.exe
真的有不同的作用!查看cmd.exe /?
的文档会显示以下内容:
如果指定/ c或/ k,则cmd处理字符串的剩余部分并保留引号
试验一下,我发现/C
选项会抛出正常的命令行处理窗口!
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
之外,你的问题没有解决办法。
答案 2 :(得分:2)
正如其他答案已经指出的那样,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
。