0

What are the advantages of using list over string in subprocess methods? The ones I understand so far:

  • Security if input comes from external sources
  • Portability over different operating systems

Are there any others?

In my particular case, I'm using subprocess library to run tests on a software. Input does not come from external source. Tests are run only on Linux. Therefore, I see no benefit of lists over strings.

4
  • Do you mean, why pass a list as the args parameter to Popen, instead of a string? The documentation discusses how the input is treated differently depending on its type. Commented Mar 24, 2014 at 15:52
  • 1
    Do you mean instead of using shell=True? If you use that, you should use a string for cross platform compatibility. Otherwise, use a list with shell=False. It avoids the overhead of spawning a shell when you don't need it, but still allows you to pass commandline arguments. Commented Mar 24, 2014 at 15:53
  • So using shell=False and parameter list as input is faster than using shell=True and string as input? So that is an additional benefit. Commented Mar 24, 2014 at 16:22
  • I suppose I can shlex.split(cmd) instead of having to create the list by myself. I'll do that. Commented Mar 24, 2014 at 17:30

1 Answer 1

2

On POSIX, list and string arguments have different meaning and are used in different contexts.

You use a string argument and shell=True to run a shell command e.g.:

from subprocess import check_output

output = check_output("dmesg | grep hda", shell=True)

A list argument is used to run a command without the shell e.g.:

from subprocess import check_call

check_call(["ls", "-l"])

One exception is that call("ls") is equivalent to call(["ls"]) (a command with no arguments).

You should use a list argument with shell=False (default) except in those cases when you need the shell so the string argument is used.

It is almost always an error to use a list argument and shell=True (the arguments are interpreted as arguments to the shell itself instead of the command in this case). Don't use it.

If your question: what are the advantages of shell=False and hence the list argument over a string argument:

  • you don't need to escape the arguments, no shell interpolation such as word splitting, parameter expansion, command substitution occurs: what you see is what you get
    • support for arguments with spaces
    • support for arguments with special characters such as quotes, dollar sign, etc
  • it is clear where arguments boundaries are. They are explicitely separated.
  • it is clear what program is executed: it is the first item in the list
  • an argument that is populated from an untrusted source won't be able to execute arbitrary commands
  • why run a superfluous shell process unless you need it

Sometimes, it might be more convenient/readable to specify an argument as a string in the source code; shlex.split() could be used to convert it to a list:

import shlex
from subprocess import check_call

cmd = shlex.split('/bin/vikings -input eggs.txt -output "spam spam.txt" '
                  '''-cmd "echo '$MONEY'"''')
check_call(cmd)

See the docs.


On Windows, the arguments are interpreted differently. The native format is a string and the passed list is converted to a string using subprocess.list2cmdline() function that may not work for all Windows programs. shell=True is only necessary to run builtin shell commands.

If list2cmdline() creates a correct command line for your executable (different programs may use different rules for interpreting the command line) then a list argument could be used for portability and to avoid escaping separate arguments manually.

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

Comments

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.