我有以下代码用于从程序中运行批处理脚本:
#include <string>
#include <tchar.h>
#include <iostream>
int main()
{
std::wstring command = _T("\"C:\\cygwin64\\home\\ravik\\path with space\\sample.bat\"");
std::wstring arg1 = _T("C:\\cygwin64\\home\\ravik\\another_space\\test");
std::wstring arg2 = _T("\"C:\\cygwin64\\home\\ravik\\another space\\test\"");
std::wstring fullCommand1 = command + _T(" ") + arg1;
_wsystem(fullCommand1.c_str());
std::wstring fullCommand2 = command + _T(" ") + arg2;
_wsystem(fullCommand2.c_str());
std::cin.get();
return 0;
}
在fullCommand1
和fullCommand2
中,我使用相同的命令(即sample.bat
),但将不同的命令行参数传递给所述命令(arg1
vs { {1}})。但是,虽然arg2
命令在使用_wsystem
时按预期工作,但当我使用fullCommand1
时,我收到错误
'C:\ cygwin64 \ home \ ravik \ path'未被识别为内部或外部命令,可操作程序或批处理文件。
看来我的fullCommand2
周围的"
在第二次调用path with space
时消失了。造成这种情况的原因是什么?
答案 0 :(得分:3)
为什么会这样?
在Microsoft C运行时的system()和_wsystem()实现中存在一个设计缺陷,在这种情况下会使你绊倒。
您尝试运行的命令如下所示:
"c:\path with spaces\my.bat" "argument with spaces"
C运行时采用最简单的方法,将其转换为
cmd /c "c:\path with spaces\my.bat" "argument with spaces"
不幸的是,当请求命令中的第一个字符是引号时,cmd.exe
有rather arcane rules,在这种情况下最终会将命令解释为
c:\path with spaces\my.bat" "argument with spaces
由于显而易见的原因无效。
(我说这是一个设计缺陷,因为如果运行时使用/ S开关并在命令周围添加引号,它将在每种情况下都能正常工作。出于向后兼容性原因,这可能无法修复。或许它可能是只是不是运行时开发团队的优先事项。)
无论原因是什么,结果是你必须自己处理问题。
如何解决此特定情况?
在这种特殊情况下,最简单的解决方案是使用如下命令:
""c:\path with spaces\my.bat" "argument with spaces""
运行时会将其转换为
cmd /c ""c:\path with spaces\my.bat" "argument with spaces""
将被解释为所需,因为有两个以上的引号。在使用这种方法时,您只需要小心一点,因为它可能会导致混淆,即有时只需要额外的引号。
(即使不需要额外的引号,几乎总是安全的,但是如果可执行文件的路径与命令行参数相结合,则存在潜在的歧义碰巧形成了一个通往不同可执行文件的有效路径。请参阅上面链接的答案的附录中的一个例子,尽管是一个相当人为的!)
如何解决一般情况?
最常见的解决方案是将命令字符串指定为
cmd /s /c ""c:\path with spaces\my.bat" "argument with spaces""
运行时将其转换为
cmd /c cmd /s /c ""c:\path with spaces\my.bat" "argument with spaces""
将运行
cmd /s /c ""c:\path with spaces\my.bat" "argument with spaces""
将被解释为
"c:\path with spaces\my.bat" "argument with spaces"
根据需要;由于/ S标志,即使您运行的命令没有任何引号,此变体也将始终按预期工作。
这种方法确实意味着有两个cmd.exe
被启动的实例,一个在另一个内;如果这种轻微的开销是不可接受的,你总是可以选择直接使用CreateProcess而不是调用system()。
(另一种最好自己调用CreateProcess的情况是你需要在命令行上使用插入符号或其他特殊字符。)