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', 'https://github.com/achedeuzot/project',
'/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', 'https://github.com/achedeuzot/project',
'/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
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
.
source to share
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], ...])
source to share