Странная ошибка 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], ...])