Strange python error with subprocess.check_call

I have a very strange error with a python function subprocess.check_call()

. Here are two tests that should fail due to permission issues, but the first only returns "use" ("unexpected behavior"):

# Test #1
import subprocess
subprocess.check_call(['git', 'clone', '',
                       '/var/vhosts/project'], shell=True)

# Shell output
usage: git [--version] [--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]
           [-p|--paginate|--no-pager] [--no-replace-objects] [--bare]
           [--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]
           [-c name=value] [--help]
           <command> [<args>]

The most commonly used git commands are:


Now for the second test ("expected behavior"):

# Test #2
import subprocess
subprocess.check_call(' '.join(['git', 'clone', '',
                                '/var/vhosts/project']), shell=True)
# Here, we're making it into a string, but the call should be *exactly* the same.

# Shell output
fatal: could not create work tree dir '/var/vhosts/project'.: Permission denied


This second mistake is correct. I do not have rights. But why is there a difference between the two calls? I thought using a single string or list is the same as a function check_call()

. I have read the python documentation and various use cases and both appear to be correct.

Has anyone had the same strange error? Or does someone know why there is a difference in output when the commands should be exactly the same?

Side notes: Python 3.4


source to share

2 answers

Remove shell=True

from the first. If you read the subprocess module documentation carefully, you will see. If shell=False

(default), the first argument is a command line list with arguments and all (or a line with only a command, no arguments). If shell = True then the first argument is a string representing the shell command line, the shell is executed, which in turn parses your command line and separates the space (+ much more dangerous things you might not want to do)) ... If the shell=True

first argument is also a list, then the first item in the list is the shell command line, and the rest are passed as arguments to the shell, not a command

If you don't know what you really need, you always need to shell=False




Here's the relevant bit from the documentation:

If args is a sequence, the first element specifies the command line, and any additional elements will be treated as additional arguments to the shell itself. That is, Popen does the equivalent:

Popen(['/bin/sh', '-c', args[0], args[1], ...])



All Articles