Странная ошибка Python с subprocess.check_call

У меня действительно странная ошибка с питоном subprocess.check_call() функция. Вот два теста, которые оба должны потерпеть неудачу из-за проблем с разрешениями, но первый возвращает только "использование" ("неожиданное поведение"):

# 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:
[...]

Теперь для второго теста ("ожидаемое поведение"):

# 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

Эта вторая ошибка является правильной. У меня действительно нет разрешений. Но почему есть разница между двумя вызовами? Я думал, что с помощью одной строки или списка то же самое с check_call() функция. Я прочитал документацию по Python и различные примеры использования, и оба выглядят правильно.

У кого-то была такая же странная ошибка? Или кто-то знает, почему есть разница в выводе, когда команды должны быть точно такими же?

Примечания: Python 3.4

2 ответа

Решение

Удалить shell=True с первого. Если вы внимательно перечитаете документацию модуля подпроцесса, то увидите. Если shell=False (по умолчанию) первый аргумент - это список командной строки с аргументами и всеми (или строка только с командой, без аргументов). Если shell=True, то первым аргументом является строка, представляющая командную строку оболочки, выполняется оболочка, которая, в свою очередь, анализирует для вас командную строку и разделяет ее на пробелы (+ гораздо более опасные вещи, которые вы, возможно, не захотите делать)). Если shell=True и первый аргумент является списком, затем первый элемент списка является командной строкой оболочки, а остальные передаются в качестве аргументов оболочке, а не команде.

Если вы не знаете, что вам действительно нужно, всегда позволяйте shell=False,

Вот соответствующий бит из документации:

Если args является последовательностью, первый элемент задает командную строку, и любые дополнительные элементы будут рассматриваться как дополнительные аргументы самой оболочки. То есть Попен делает эквивалент:

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

Другие вопросы по тегам