29

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!

14
  • 14
    Whoever thought that putting spaces into filenames would be "a good idea" should be shot. Commented Apr 1, 2012 at 13:51
  • 3
    I guess that would be Microsoft? Lots of stuff broke when people's work wound up in C:\Documents and Settings. Commented Apr 1, 2012 at 13:52
  • 1
    I thought that calling system("cd ...") and then system("pdftotext" ...) would call two different cmd windows instead of calling it in the same cmd? Commented Apr 1, 2012 at 13:57
  • 2
    @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. Commented Apr 1, 2012 at 14:05
  • 1
    @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! Commented Apr 1, 2012 at 14:21

3 Answers 3

41

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
Sign up to request clarification or add additional context in comments.

2 Comments

@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.
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!
5

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.

Comments

0

Good learning from here on the internals of System call.Same issue reproducible(of course) with C++ string, TCHARs etc. One approach that always helped me is SetCurrentDirectory() call. I first set current path and then execute. This has worked for me so far. Any comments welcome. -Sreejith. D. Menon

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.