achedeuzot
achedeuzot

Reputation: 4384

Strange python error with subprocess.check_call

I'm having a really strange error with the python subprocess.check_call() function. Here are two tests that should both fail because of permission problems, but the first one only returns a 'usage' (the "unexpected behaviour"):

# 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 (the "expected behaviour" one):

# 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 error is the correct one. I don't have the permissions indeed. But why is there a difference between the two calls ? I thought that using a single string or a list is the same with the check_call() function. I have read the python documentation and various usage examples and both look correct.

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

Side notes: Python 3.4

Upvotes: 3

Views: 444

Answers (2)

Here's the relevant bit from the documentation:

If args is a sequence, the first item specifies the command string, and any additional items will be treated as additional arguments to the shell itself. That is to say, Popen does the equivalent of:

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

Upvotes: 0

Anton
Anton

Reputation: 4611

Remove shell=True from the first one. If you carefully reread the subprocess module documentation you will see. If shell=False (default) the first argument is a list of the command line with arguments and all (or a string with only the command, no arguments supplied at all). If shell=True, then the first argument is a string representing a shell command line, a shell is executed, which in turn parses the command line for you and splits by white space (+ much more dangerous things you might not want it to do). If shell=True and the first argument is a list, then the first list item is the shell command line, and the rest are passed as arguments to the shell, not the command.

Unless you know you really, really need to, always let shell=False.

Upvotes: 3

Related Questions