如何在Windows上使用std::system运行带有空格的可执行文件

How to run an executable with spaces using std::system on Windows

本文关键字:运行 system 行带 空格 可执行文件 std Windows      更新时间:2023-10-16

如何在不使用C++11的情况下在Windows上使用std::system运行带有空格的可执行文件?

我已经尝试了在带有空格的路径周围放置引号看似明显的引号,但是在运行命令弹出的控制台窗口中,我收到一条消息,指示完整的可执行路径正在空格上拆分。 例如,我尝试了以下方法:

#include <cstdlib>
int main()
{
    int no_spaces_forward_rc = std::system("c:/IronPython2.7/ipy -c "print 'no_spaces_forward'"");
    // no_spaces_forward_rc is 0 and "no_spaces_forward" is written to console window
    int spaces_forward_rc    = std::system(""c:/Program Files (x86)/IronPython 2.7/ipy" -c "print 'spaces_forward'"");
    // spaces_forward_rc is 1, and "'c:/Program' is not recognized as an internal or external command, operable program or batch file." is written to console window
    int no_spaces_backward_rc = std::system("c:\IronPython2.7\ipy -c "print 'no_spaces_backward'"");
    // no_spaces_backward_rc is 0 and "no_spaces_backward" is written to console window
    int spaces_backward_rc    = std::system(""c:\Program Files (x86)\IronPython 2.7\ipy" -c "print 'spaces_backward'"");
    // spaces_backward_rc is 1, and "'c:Program' is not recognized as an internal or external command, operable program or batch file." is written to console window
    int no_spaces_double_backward_rc = std::system("c:\\IronPython2.7\\ipy -c "print 'no_spaces_double_backward'"");
    // no_spaces_double_backward_rc is 0, and no_spaces_double_backward is written to console window
    int spaces_double_backward_rc    = std::system(""c:\\Program Files (x86)\\IronPython 2.7\\ipy" -c "print 'spaces_double_backward'"");
    // spaces_double_backward_rc is 1, and "'c:\Program' is not recognized as an internal or external command, operable program or batch file." is written to console window
    int spaces_double_double_backward_rc    = std::system("\"c:\\Program Files (x86)\\IronPython 2.7\\ipy\" -c "print 'spaces_double_double_backward'"");
    // spaces_dobule_double_backward_rc is 1, and "'"c:\Program Files (x86)\IronPython 2.7\ipy"' is not recognized as an internal or external command, operable program or batch file." is written to console window
    return 0;
}

我已经验证了直接在cmd提示符下运行"c:Program Files (x86)IronPython 2.7ipy" -c "print 'spaces_backward'"有效,而且我很确定我不只是有错字。 这让我发疯 - 任何帮助将不胜感激!

(我正在使用Visual Studio 2012并使用子系统控制台进行编译,如果有帮助的话。

cmd.exe的语法有一个令人讨厌的扭曲。 从cmd.exe /?

1.  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.

为了使行为一致,std::system调用应使用 /S 开关,并将命令嵌入引号中。 可悲的是,事实并非如此。 这意味着这将起作用:

std::system(""c:\Program Files (x86)\Adobe\Reader 10.0\Reader\AcroRd32.exe" h:\documents\documentation\misc\calendar 1999.pdf");

但这个看似微不足道的变体不会:

std::system(""c:\Program Files (x86)\Adobe\Reader 10.0\Reader\AcroRd32.exe" "h:\documents\documentation\misc\calendar 1999.pdf"");

若要解决此问题,整个命令(包括可执行文件的引用路径必须用引号括起来:

std::system("""c:\Program Files (x86)\Adobe\Reader 10.0\Reader\AcroRd32.exe" "h:\documents\documentation\misc\calendar 1999.pdf""");

在您的示例中,这将是

std::system("""c:\Program Files (x86)\IronPython 2.7\ipy" -c "print 'spaces_backward'""");

好的,这段代码使用原始字符串文字,实际上对我有用(VS2013 Express):

std::string cmd = R"cmd("C:Program Files (x86)doxygenbindoxygen.exe")cmd";
system(cmd.c_str());

对于不受支持的原始字符串文本,传统上转义的字符串文本应如下所示 1:

std::string cmd = ""C:\Program Files (x86)\doxygen\bin\doxygen.exe"";

这些双重转义的原因是,system()实际上调用cmd,它期望双引号"将命令行括起来执行。


1)很容易看出,这很容易在某处错过

为了方便起见,我写了一个小类command,它封装了 Harry Johnston 的解决方案,并使引用路径空间的使用system变得非常容易。

用法:

ifs::win::command c;
std::filesystem::path source = "c:\my folder\file.txt";
std::filesystem::path destination = "c:\another folder\another file.txt";
try {
    c << "copy " << source << " " << destination;
    c.run();
}
catch (ifs::win::cmd_error& e) {
    std::cout << "command: " << e.command() << std::endl;
    std::cout << "result: " << e.res() << std::endl;
    std::cout << "default error message: " << e.what() << std::endl;
}

从此存储库获取ifs_win.h/cpp

(还有std::string runAndGetOutput();

在 Win10 和 Win11 上使用 c++17 进行测试。