0

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?

5
  • 1
    Try replacing args with str(args) Commented Sep 26, 2016 at 3:20
  • Thanks, I gave that a go but it doesn't seem to have had any effect. call() is still interpreting the variable with quotes. Commented Sep 26, 2016 at 3:30
  • Your code isn't actually passing in the parameters, but I think we can guess what you mean. Commented Sep 26, 2016 at 3:58
  • You don't have to include exit when calling a shell; it will exit when it has completed your commands (and it's hard to imagine what would happen if this wasn't the case). Commented Sep 26, 2016 at 3:59
  • Yeah, I actually included that in this post by mistake. I was trying a really primitive workaround to prevent something like an & affecting the shell. Commented Sep 26, 2016 at 4:05

2 Answers 2

1

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

Sign up to request clarification or add additional context in comments.

5 Comments

Indeed, make args a list instead, and call(['mednafen'] + args + [romname])
This is giving me the same results. call() is parsing the contents of args with quotes included.
That's because you forgot to turn it into a list with each argument instead of a string with all arguments.
I created a list with the arguments and the result was the same.
@MikeIronFist args = ["-fs", "1"] <- this is how your list should like. Then it will work. ☺
1

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))

2 Comments

In this case, shlex.split works, but if you can have your arguments as proper list (["-fs", "1"]) right away, you should do that instead of using shlex.split, which has lots of functionality which may come at a surprise (handling of quotes and such). With subprocess, Python gives you a great tool to avoid all the pitfalls of spaces and quoting by simply passing python strings correctly as one argument each. Use that power.
That's extremely helpful! Thanks a lot. This really clears up how subprocess handles programs/arguments for me.

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.