Search code examples
pythonsubprocesspopenos.path

Issues with Python Popen() (Syntax?)


have a small issue with a program I am trying to launch from a Python script via Popen() (I understand Popen() may not be ideal, but I am working with somewhat of a template used in other instances, and want to follow convention).

I am a bit confused, as I can't seem to get the following to run:

root = os.getcwd()

bin = 'my_executable.exe'

bin_fullpath = os.path.join(root,bin)

params = 'Option C -f Module -y -q'

p = subprocess.Popen([bin_fullpath,params])

out = p.communicate()

The program launches, but exits with error code 1 (I checked with check_call).

However, when I forgo the above method, and simply provide the entire string I need to run, as follows:

subprocess.Popen(r'C:\Users\me\Desktop\path\to\tool\my_executable.exe Option C -f Module -y -q')

The program executes as expected. Obviously I have something wrong with the sytntax, but I can't figure out what . . .

Any insight would be greatly appreciated!


Solution

  • When you use the "list of arguments" format, each one has to be its own string, as a separate member of the list, like this:

    params = ['Option', 'C', '-f', 'Module', '-y', '-q']
    p = subprocess.Popen([bin_fullpath, *params])
    

    When you put them all in a single string, you're telling subprocess they're all one big argument.1 So, rather than being the rough equivalent of this command line:

    C:\Users\me\Desktop\path\to\tool\my_executable.exe Option C -f Module -y -q
    

    … it's the rough equivalent of this one:

    C:\Users\me\Desktop\path\to\tool\my_executable.exe "Option C -f Module -y -q"
    

    If it's not clear why those are different, consider these examples instead:

    fix.exe "My Pictures\picture1.jpg"
    fix.exe My Pictures\picture1.jpg
    

    The first one is fixing one picture, My Pictures\picture1.jpg. The second is fixing two pictures, My, and Pictures\picture1.jpg.


    For more details on the args argument, see Frequently Used Arguments. Notice the "one big string" version is actually not valid without shell=True—even though it happens to usually work on Windows.


    1. Things are a little more complicated than this on Windows, because subprocess actually has to take all of the args and work out how to put them together in a string so that they can be parsed back into the actual separate values the way you asked for them. But never mind that.