jremedy
jremedy

Reputation: 137

python subprocess run works with single string but not list of strings

I'm trying to initiate a command-line program with command-line options from my Python script using the run method from the subprocess module.

My command is defined as a list of strings specifying the program and options as follows (where pheno_fp and construction_fp are strings representing file paths in my system and exe is a string representing the file path to the program I'm running):

    step1_cmd = [exe, 
                "--step 1",
                "--p " + pheno_fp,
                "--b 1000",
                "--o " + construction_fp + "dpw_leaveout"]

Not working - When I try the following, the program I want to run is started but the command I've specified is interpreted incorrectly because the program exits with an error saying "specify output file path with --o flag":

    test1 = subprocess.run(step1_cmd)

Working - When I try the following, the program executes correctly, meaning all arguments are interpreted as intended:

    test1 = subprocess.run(" ".join(step1_cmd), shell=True)

If I understood the documentation correctly, the former approach is the recommended usage but I can't understand why it's not working. I'm pretty sure it's formatted the same as the examples in the documentation so I'm a bit stumped. Any ideas?

Upvotes: 3

Views: 3042

Answers (2)

user2314737
user2314737

Reputation: 29317

The explanation for this behavior is here:

args is required for all calls and should be a string, or a sequence of program arguments. Providing a sequence of arguments is generally preferred, as it allows the module to take care of any required escaping and quoting of arguments (e.g. to permit spaces in file names).

Example: the sequence

l = ['ls', '-l tmp'] 

gives an error

subprocess.run(l)                                                                                                                                                      
ls: illegal option --  

This is because subprocess (which is a call to Popen) is trying to run ls "-l tmp" .

The correct way to define a sequence of arguments is by separating them so that they can be quoted correctly

subprocess.run(['ls', '-l', 'tmp']) 

Upvotes: 2

Zionsof
Zionsof

Reputation: 1246

Split each parameter with its value, like so:

step1_cmd = [exe, 
             "--step",
             "1",
             "--p",
             str(pheno_fp),  # if it isn't a string already
             "--b",
             "1000",
             "--o",
             str(construction_fp) + "dpw_leaveout"
]

Because when passing a list of parameters, each part is separated with a space, both options and their values

Upvotes: 4

Related Questions