我正在尝试使用 mingw 调用 popen() ,如下所示:
#define RUN_COMMAND "\"C:\\Program Files\\CA\\BrightStor ARCserve Backup\\ca_qmgr.exe\" \"-list\""
int main() {
outputPointer = popen(RUN_COMMAND, "r");
...
}
但我无法让它工作。我认为这是一个引用的噩梦......
事实证明, popen 函数将整个事物周围的引号去掉,例如。"C:/Program Files"
变成C:/Program Files
和"Ab cd.exe" "ef gh"
变成ab cd" "ef gh
。您可以通过在整个内容周围添加引号来解决此问题,例如。""ab cd.exe" "ef gh""
这变得"ab cd.exe" "ef gh"
如预期。
该解决方案的灵感来自Kaz的回复
事实证明,这个问题是可以解决的。(不过,与 Windows 中的大多数东西一样,不是 100%)。
该popen
函数打开一个系统命令,这意味着它几乎可以肯定只是将字符串参数插入到cmd.exe /c <here>
.
在 Windows 命令提示符下进行了一些交互式实验之后cmd.exe /c
,我们找到了一种运行路径名中有空格的程序的方法。
用引号天真的尝试,不:
C:\>cmd /c "foo bar"
'foo' is not recognized as an internal or external command,
operable program or batch file.
我们可以用抑扬符转义引号吗?
C:\>cmd /c ^"foo bar^"
'foo' is not recognized [...]
空间怎么样?
C:\>cmd /c foo^ bar
'foo' is not recognized [...]
只引用空格怎么样?
C:\>cmd /c foo" "bar
'foo" "bar' is not recognized as an internal or external command,
operable program or batch file.
啊哈!这是有前途的!它实际上是在尝试运行foo bar
吗?让我们来看看:
C:\>copy con "foo bar.bat"
echo i am foo bar
^Z
1 file(s) copied.
C:\>cmd /c foo" "bar
C:\>echo i am foo bar
i am foo bar
啊哈!我们的批处理文件在其名称中有一个空格已运行!
所以,现在我在 Visual Studio 2008 中尝试以下操作:
#include <stdio.h>
int main()
{
FILE *in = _popen("C:\\Program\" \"Files\\Internet\" \"Explorer\\iexplore.exe", "r");
if (in) {
char line[200];
printf("successfully opened!\n");
if (fgets(line, 200, in))
fputs(line, stdout);
_pclose(in);
}
return 0;
}
它可以很好地启动 Internet Explorer,然后一直阻塞,fgets
直到您退出浏览器(并且由于没有输出而无法读取任何内容)。
它在使用 Microsoft C 运行时库的 MinGW 中工作;事实上,我想出了这个解决方案来修复使用 MinGW 移植到 Windows 的编程语言库中的错误。
这种转义技巧不会逃脱前导空格。它似乎确实适用于尾随空格。两者都不是问题。我们不经常看到以空格开头或结尾的路径名,更不用说可执行路径名了。
我也找不到一种方法来逃避可能作为路径的一部分出现的嵌入式双引号,同时处理空格。人们在创建类似C:\Program Files\Bob's so-called "editor"\bedit.exe
.
看看win32 api 中的 posix popen 是什么等价物。我_popen()
很久以前就放弃了在 Windows 下使用的尝试。纯 WIN32 解决方案的性能要可靠得多。
如果 mingw 将您的参数传递给sh -c
而不是cmd.exe /c
,那么您可能希望将这些反斜杠更改为正斜杠。像下面这样的东西应该可以解决问题。
"\"C:/Program Files/CA/BrightStor ARCserve Backup/ca_qmgr.exe\" -list"
我刚刚遇到这个问题,并尝试了 Kaz 的解决方案,但没有成功。我解决它的方法是简单地更改目录,在没有可执行文件路径的情况下执行 _popen,然后改回原始目录。
char cwd[MAX_PATH];
_getcwd(cwd, MAX_PATH);
if (_chdir("C:\\Program Files\\CA\\BrightStor ARCserve Backup") >= 0)
{
outputPointer = _popen("ca_qmgr.exe \"-list\"", "r");
_chdir(cwd);
}
根据 popen 的手册页:
command 参数是指向包含 shell 命令行的以 null 结尾的字符串的指针。该命令使用 -c 标志传递给 /bin/sh;解释(如果有)由 shell 执行。
所以你想要的是转义sh
要解析的字符串。您不需要转义-list
参数,您可以尝试转义空格而不是引用整个程序名称。我这里没有要测试的 Windows 系统,但我建议
#define RUN_COMMAND "C:\\Program Files\\CA\\BrightStor\\ ARCserve\\ Backup\\ca_qmgr.exe -list"
int main() {
outputPointer = popen(RUN_COMMAND, "r");
...
}