jotNewie
jotNewie

Reputation: 496

Avoid shell=True with command line arguments in python

I want to run inside my test.py script a shell command line which takes a couple of arguments. The test.py is run as:

python test.py filename file_2 int

The test.py looks inside analogous to this:

import sys

filename = sys.argv[1]
file_2 = sys.argv[2]
num = sys.argv[3]

subprocess.call("xargs /bin/bash  build/install/programme/bin/programme option -n "+num+" --csv-file="+str(filename)+" -c files/"+str(file_2)+ "< /tmp/my_ids_"+str(file_2)+"_"+str(num),shell=True)

The point is that I want to avoid using shell=True, but all the options I found so far do not provide a good solution for the arguments I am adding in the command line.

So far I have tried different options via splitting it with Popen, as for example:

import sys

filename = sys.argv[1]
file_2 = sys.argv[2]
num = sys.argv[3]

subprocess.Popen(["xargs","/bin/bash","build/install/programme/bin/programme","option","-n", str(num),"--csv-file=",str(filename),"-c","files/",str(file_2),"<",str("/tmp/my_ids_"+str(file_2)+"_"+str(num))])

But I got no working results. Also tried with shlex, but again in the documentation I saw no options for being able to add arguments in the command.

Thanks in advance for your help!

Upvotes: 0

Views: 278

Answers (1)

Charles Duffy
Charles Duffy

Reputation: 295687

Your original code was equivalent to running the following bash command:

xargs \
  /bin/bash \
  build/install/programme/bin/programme \
  option \
  -n            "$int" \
  "--csv-file=" "$filename" \
  -c            "files/"           "${file_2}" \
  '<'           "/tmp/my_ids_${file_2}_${int}"

That wouldn't have worked either, and for all the same reasons.


import sys

filename = sys.argv[1]
file_2 = sys.argv[2]
num = int(sys.argv[3])

subprocess.Popen([
  "xargs",
  "/bin/bash",
  "build/install/programme/bin/programme",
  "option",
  "-n", str(num),
  "--csv-file=%s" % filename,
  "-c", "files/%s" % file_2,
], stdin=open("/tmp/my_ids_%s_%s" % (file_2, num), 'r')

Note the differences:

  • A single argument is always passed as a single list member. That means --csv-file=filename is all one thing, and that the prefix files/ and the string contained in the variable file_2 need to be passed within the same list element.
  • Redirections (<) are instructions to the shell, not arguments to your program. You thus can't use them here, but should use other options (such as the stdin and stdout arguments to Popen) to simulate their effect.
  • int is the name of the integer type; using the variable name num keeps the original name available.

Upvotes: 2

Related Questions