C++ system() command path with spaces

2019-03-06 03:25发布

问题:

How do I use the system() function in c++ if I want to enter a command that needs a path when my path has spaces in it? Example code:

#include <iostream>

int main()
{
    std::string command = "ls -la /home/testuser/this is a folder/test/";
    std::cout << "Click enter to execute command..." << std::endl;
    getchar();
    std::system(command.c_str());
    return 0;
}

This doesn't work supposedly because the shell needs backspaces in front of a space. Unfortunately this doesn't work too:

std::string command = "ls -la /home/testuser/this\b is\b a\b folder/test/";

Any idea what I'm doing wrong or how I could do it better? Thanks.

回答1:

Ask yourself: how would you execute this command, yourself, from a shell prompt?

$ ls -la /home/testuser/this is a folder/test/

This, of course, will not work for the same reason your program fails. Instead, as every primer on shell scripting teaches you, you need to quote the parameter:

$ ls -la "/home/testuser/this is a folder/test/"

That will work, and you use system() in exactly the same way:

std::string command = "ls -la \"/home/testuser/this is a folder/test/\"";

But what's even better is not using system() in the first place. All the system() is, for all practical purposes, is a fork(), followed by exec() in the child process, with the parent process wait()ing for the child process's termination.

The problem is that the child process exec() the system shell, which parses the command according to its rules. This includes all the normal things that occur when executing the command via the shell directly: filename expansion, globbing, and other things.

If the string that gets passed to exec() includes any special shell characters, they'll be interpreted by the shell. In this case, you're intentionally using this to correctly parse the command string, in order to pass the correct arguments to /bin/ls.

When executing a specific, fixed command, this is fine. But when the actual command varies, or contains externally-specified parameters, it is your responsibility to correctly handle any shell wildcard characters in order to get your intended result. Hillarity ensues, otherwise. In that situation, you will find that using fork() and exec() yourself will produce far more deterministic, and reliable results, where you are in complete control of all arguments that get passed to the command being executed, instead of relying on the system shell to do it for you.