Reputation: 13130
How can an executable with spaces be run using std::system on Windows without using C++11?
I've tried the seemingly obvious placing quotes around the path with spaces, but in the console window that pops up running the command I get a message that indicates that the full executable path is being split on spaces. For example, I've tried the following:
#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;
}
I've verified that running "c:\Program Files (x86)\IronPython 2.7\ipy" -c "print 'spaces_backward'"
directly in a cmd prompt works, and I'm pretty sure I don't just have a typo. This is driving me nuts -- any help would be greatly appreciated!
(I'm using Visual Studio 2012 and compiling with subsystem Console if that helps.)
Upvotes: 6
Views: 5591
Reputation: 1
For convenience, I wrote a little class command
that encapsulates Harry Johnston's solution and makes using system
for quoted paths spaces very easy.
Usage:
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;
}
Get ifs_win.h/cpp
from this repo.
(There is also std::string runAndGetOutput();
)
Tested with c++17 on Win10 and Win11.
Upvotes: 0
Reputation: 36328
The syntax for cmd.exe
has a nasty twist. From 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.
To make the behaviour consistent, the std::system
call should use the /S
switch, and embed the command in quote marks. Sadly, it doesn't. This means that this will work:
std::system("\"c:\\Program Files (x86)\\Adobe\\Reader 10.0\\Reader\\AcroRd32.exe\" h:\\documents\\documentation\\misc\\calendar 1999.pdf");
but this seemingly trivial variant won't:
std::system("\"c:\\Program Files (x86)\\Adobe\\Reader 10.0\\Reader\\AcroRd32.exe\" \"h:\\documents\\documentation\\misc\\calendar 1999.pdf\"");
To fix the problem, the entire command, including the quoted path to the executable, must be surrounded in quotes:
std::system("\"\"c:\\Program Files (x86)\\Adobe\\Reader 10.0\\Reader\\AcroRd32.exe\" \"h:\\documents\\documentation\\misc\\calendar 1999.pdf\"\"");
In your example, that would be
std::system("\"\"c:\\Program Files (x86)\\IronPython 2.7\\ipy\" -c \"print 'spaces_backward'\"\"");
Upvotes: 8
Reputation: 1
OK this code using a raw string literal, actually works for me (VS2013 Express):
std::string cmd = R"cmd("C:\Program Files (x86)\doxygen\bin\doxygen.exe")cmd";
system(cmd.c_str());
For unsupported raw string literals, the traditionally escaped string literal should look as follows 1:
std::string cmd = "\"C:\\Program Files (x86)\\doxygen\\bin\\doxygen.exe\"";
The reason for these double escapings is, that system()
actually calls cmd
which expects double quotes "
enclosing the command line to execute.
1) As easy to see, this is error prone for missing a \
somewhere.
Upvotes: 0