C++ system() not working when there are spaces in two different parameters

23,327

Solution 1

system() runs command as cmd /C command. And here's citation from cmd doc:

If /C or /K is specified, then the remainder of the command line after
the switch is processed as a command line, where the following logic is
used to process quote (") characters:

    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.

    2.  Otherwise, old behavior is to see if the first character is
        a quote character and if so, strip the leading character and
        remove the last quote character on the command line, preserving
        any text after the last quote character.

It seems that you are hitting case 2, and cmd thinks that the whole string C:\Users\Adam\Desktop\pdftotext" -layout "C:\Users\Adam\Desktop\week 4.pdf (i.e. without the first and the last quote) is the name of executable.

So the solution would be to wrap the whole command in extra quotes:

//system("\"D:\\test\" nospaces \"text with spaces\"");//gives same error as you're getting
system("\"\"D:\\test\" nospaces \"text with spaces\"\""); //ok, works

And this is very weird. I think it's also a good idea to add /S just to make sure it will always parse the string by the case 2:

system("cmd /S /C \"\"D:\\test\" nospaces \"text with spaces\"\""); //also works

Solution 2

I got here looking for an answer, and this is the code that I came up with (and I was this explicit for the benefit of next person maintaining my code):

std::stringstream ss;
std::string pathOfCommand;
std::string pathOfInputFile;

// some code to set values for paths

ss << "\"";                             // command opening quote
ss << "\"" << pathOfCommand   << "\" "; // Quoted binary (could have spaces)
ss << "\"" << pathOfInputFile << "\"";  // Quoted input (could have spaces)
ss << "\"";                             // command closing quote
system( ss.str().c_str() );             // Execute the command

and it solved all of my problems.

Share:
23,327

Related videos on Youtube

Adam Smith
Author by

Adam Smith

Updated on January 16, 2022

Comments

  • Adam Smith
    Adam Smith over 2 years

    I'm trying to run a .exe that requires some parameters by using system().

    If there's a space in the .exe's path AND in the path of a file passed in parameters, I get the following error:

    The filename, directory name, or volume label syntax is incorrect.
    

    Here is the code that generates that error:

    #include <stdlib.h>
    #include <conio.h>
    
    int main (){
        system("\"C:\\Users\\Adam\\Desktop\\pdftotext\" -layout \"C:\\Users\\Adam\\Desktop\\week 4.pdf\"");
        _getch();
    }
    

    If the "pdftotext"'s path doesn't use quotation marks (I need them because sometimes the directory will have spaces), everything works fine. Also, if I put what's in "system()" in a string and output it and I copy it in an actual command window, it works.

    I thought that maybe I could chain some commands using something like this:

    cd C:\Users\Adam\Desktop;
    pdftotext -layout "week 4.pdf"
    

    So I would already be in the correct directory, but I don't know how to use multiple commands in the same system() function.

    Can anyone tell me why my command doesn't work or if the second way I thought about would work?

    Edit: Looks like I needed an extra set of quotation marks because system() passes its arguments to cmd /k, so it needs to be in quotations. I found it here:

    C++: How to make a my program open a .exe with optional args

    so I'll vote to close as duplicate since the questions are pretty close even though we weren't getting the same error message, thanks!

    • Kerrek SB
      Kerrek SB about 12 years
      Whoever thought that putting spaces into filenames would be "a good idea" should be shot.
    • Mike DeSimone
      Mike DeSimone about 12 years
      I guess that would be Microsoft? Lots of stuff broke when people's work wound up in C:\Documents and Settings.
    • Adam Smith
      Adam Smith about 12 years
      I know, but I don't really have a choice, I have over 1000 files to parse and they all have spaces
    • Mike DeSimone
      Mike DeSimone about 12 years
      Why use multiple commands in one system call? Make multiple system calls. system has to wait for the command to finish.
    • Adam Smith
      Adam Smith about 12 years
      I thought that calling system("cd ...") and then system("pdftotext" ...) would call two different cmd windows instead of calling it in the same cmd?
    • mah
      mah about 12 years
      @smerlin I don't know about how it works on Windows, but on *nix, that's definitely not the case because system() creates a new shell and the directory change won't bubble up.
    • Adam Smith
      Adam Smith about 12 years
      I can't even get system("cd C:") working. If I use the cd command in system and then call dir, I'm still in the project's dir (which is on a different drive)
    • hamstergene
      hamstergene about 12 years
      It works fine for me. What Windows version are you on?
    • Adam Smith
      Adam Smith about 12 years
      @hamstergene Windows 7 Professional SP1 64bits. Which one works fine? The cd thing I posted in the comments or the example code in my post?
    • hamstergene
      hamstergene about 12 years
      @AdamSmith I'm on exactly the same OS. I've tried system() with exe and bat files, with paths with and without spaces, they're all working.
    • Adam Smith
      Adam Smith about 12 years
      @hamstergene I see... Are you using an exe that can take arguments that also use spaces? Because that's the problem I was having and I just found out why (needed another set of "" since the arguments are passed to cmd /k). Thanks your replies!
    • Adam Smith
      Adam Smith about 12 years
    • smerlin
      smerlin about 12 years
      @mah: you were correct that adjacent std::system calls use different shells (on windows aswell). I thought i already used std::system("cd somedir") to change the cwd of an application, but it seems like i remembered it incorrectly.
    • Harry Johnston
      Harry Johnston about 12 years
      To run multiple commands, use & as the delimiter: system("cd xyzzy & dir");
  • hamstergene
    hamstergene about 12 years
    @AdamSmith “no /S switch” is required for case 1 to be applicable (see the doc), so it forces cmd to use the old behavior. No other effect is mentioned.
  • Adam Smith
    Adam Smith about 12 years
    Thanks for the answer, it works great! After reading the excerpt from the documentation that you posted, you're probably right and I might be better off using /S, thanks!