简体   繁体   中英

Escaping quotation marks in _wsystem

I have the following code that I use to run a batch script from within a program:

#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;
}

In both fullCommand1 and fullCommand2 , I use the same command (namely sample.bat ), but pass a different command-line argument to said command ( arg1 vs arg2 ). However, while the _wsystem command works as expected when using fullCommand1 , when I use fullCommand2 , I get the error

'C:\\cygwin64\\home\\ravik\\path' is not recognized as an internal or external command, operable program or batch file.

It appears that somehow, the " surrounding my path with space has disappeared for the second call to _wsystem . What is the cause for this?

Why does this happen?

There's a design flaw in the Microsoft C runtime's implementation of system() and _wsystem() which is tripping you up in this case.

The command you're trying to run looks like this:

"c:\path with spaces\my.bat" "argument with spaces"

The C runtime, taking the simplest possible approach, turns this into

cmd /c "c:\path with spaces\my.bat" "argument with spaces"

Unfortunately, cmd.exe has rather arcane rules when the first character in the requested command is a quote mark, and in this case winds up interpreting the command as

c:\path with spaces\my.bat" "argument with spaces

which doesn't work for obvious reasons.

(I say this is a design flaw because if the runtime used the /S switch and added quotes around the command, it would work perfectly in every case. This probably can't be fixed for backwards compatibility reasons. Or perhaps it just isn't a priority for the runtime's development team.)

Whatever the reason, the outcome is that you have to deal with the problem yourself.

How can I fix it in this particular case?

In this particular case, the simplest solution is to use a command like this:

""c:\path with spaces\my.bat" "argument with spaces""

The runtime will turn this into

cmd /c ""c:\path with spaces\my.bat" "argument with spaces""

which will be interpreted as desired, since there are more than two quote marks. You just need to be a little careful when using this approach as it may cause confusion that the extra quotes are only needed sometimes.

(It is almost always safe to put the extra quotes in even when they aren't needed, but there is a potential ambiguity - if the path to the executable combined with the command-line arguments happens to form a valid path to a different executable. See the addendum to the answer linked above for an example, albeit a rather contrived one!)

How can I fix it in the general case?

The most general solution is to specify the command string as

cmd /s /c ""c:\path with spaces\my.bat" "argument with spaces""

the runtime will turn it into

cmd /c cmd /s /c ""c:\path with spaces\my.bat" "argument with spaces""

which will run

cmd /s /c ""c:\path with spaces\my.bat" "argument with spaces""

which will be interpreted as

"c:\path with spaces\my.bat" "argument with spaces"

as desired; because of the /S flag, this variant will always work as expected even if the command you're running doesn't have any quote marks.

This approach does mean there are two instances of cmd.exe being launched, one inside the other; if this slight overhead is unacceptable, you always have the option of using CreateProcess directly rather than calling system().

(Another situation where it may be best to call CreateProcess yourself is if you need to use carets or other special characters on the command line.)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM