Mike IronFist
Mike IronFist

Reputation: 11

Using variables as arguments for a command called by subprocess in Python 2.7.x

I'm trying to create a basic function that will pass a filename and arguments to a program using call() from the subprocess module. The filename and arguments are variables. When I use call() it takes the variables but the called program reads their strings with " included.

Here's the code in question:

from subprocess import call

def mednafen():
    print "Loading "+romname+"..."
        call(["mednafen", args, romname])
        print "Mednafen closed."
romname="kirby.zip"
args="-fs 1"
mednafen()

I expected this would execute

mednafen -fs 1 kirby.zip

but instead it appears to interpret the variable's strings as this:

mednafen "-fs 1" "kirby.zip"

Because of this, mednafen isn't able to run because it can't parse an argument that starts with ". It works as expected if I use shell=True but that feature is apparently strongly discouraged because it's easy to exploit?

call("mednafen "+ args +" "+romname+"; exit", shell=True)

Is there a way to do this without using the shell=True format?

Upvotes: 0

Views: 615

Answers (2)

Mike IronFist
Mike IronFist

Reputation: 11

EDIT: The solution suggested by Jonas Wielicki is to make sure every single string that would normally be separated by spaces in shell syntax is listed as a separate item; That way call() will read them properly. shlex is unnecessary.

args = ["-fs", "1"]
call(['mednafen']+args+[rom])

My initial (less concise) solution: shlex.split() takes the variables/strings I feed it and converts them into a list of string literals, which in turn causes the called command to parse them correctly rather than interpreting the variables as strings within quotes. So instead of the argument being treated like "-fs 0" I'm getting -fs 0 like I originally wanted.

import shlex
call(shlex.split("mednafen "+args+" "+romname))

Upvotes: 1

Ignacio Vazquez-Abrams
Ignacio Vazquez-Abrams

Reputation: 798646

Well, yes. That's exactly what the documentation says it does. Create and pass a list containing the command and all arguments instead.

Upvotes: 1

Related Questions