When using subprocess.Popen what is the difference between using the executable parameter versus having the exe path as the first item in the command?

Viewed 474

I have been trying to run SAM CLI to build and run a local api through Python.

There seems to be a difference between using the executable parameter in the subprocess.Popen function vs having the path to the exe as the first item in the args list. I think this because SAM CLI is returning different responses depending on the method I have used. What is the difference between the two approaches I am taking? Why does the first method fail?

First method

subprocess.call(["build", "-u"], cwd=cwd, stdout=f, stderr=f, shell=False, executable=exe)

Fails and returns: Error: no such option: -u

Second method

subprocess.call([exe, "build", "-u"], cwd=cwd, stdout=f, stderr=f, shell=False)

Works and runs through the process.

exe stores the path to 'sam.exe'

2 Answers

When you call subprocess.call(['a', 'b', 'c']), it will call a program a passing arguments:

argv[0] = "a"
argv[1] = "b"
argv[2] = "c"

It is customary to pass the name of the invoked program as argv[0], so it is a handy shortcut to assume that the first argument is also the executable.

If you want more advanced control on the program, you can specify the executable argument. If you call subprocess.call(['x', 'b', 'c'], executable='a'), it will call a program a passing arguments:

argv[0] = "x"
argv[1] = "b"
argv[2] = "c"

Now the value of argv[0] does not match the name of the executable. Does it matter? Well, it depends on the program. Most programs do not look into it, because it just doesn't matter if you rename the program. However, some programs such as busybox are designed to be called by many different names, and they use argv[0] to make a difference.

In your case, when you call subprocess.call(["build", "-u"], executable=exe), you are running the correct program but with arguments:

argv[0] = "build"
argv[1] = "-u"

argv[0] is ignored, as it is taken as the name of the program; then it encounters -u and does not know what to do with it. Thus, the error.

The solution is to specify a sensible value for argv[0]:

subprocess.call(["SAM", "build", "-u"], executable=exe)

But then, the most sensible value is usually exe, and then you can remove the exectuable optional argument and just write:

subprocess.call([exe, "build", "-u"])

which is your working code.

From the doc string of the Popen

executable: A replacement program to execute.

      input, standard output and standard error file handles, respectively.

from further down in the code

        ...
        if shell:
            args = ["/bin/sh", "-c"] + args
            if executable:
                args[0] = executable

so the executable flag specifies which program to use and run the command. By defaults runs using shell but you can specify differently.

Related