Для Mac,
SHOW VARIABLES LIKE "%version%";
Фактически в Windows он использует cmd.exe
, когда shell=True
- он добавляет cmd.exe /c
(он фактически ищет переменную среды COMSPEC
, но по умолчанию имеет значение cmd.exe
, если нет) аргументам оболочки. (В Windows 95/98 он использует промежуточную программу w9xpopen
для фактической запуска команды).
Таким образом, странная реализация на самом деле является UNIX
, которая делает следующее (где каждое пространство разделяет другой аргумент):
/bin/sh -c gcc --version
Похоже, правильная реализация (по крайней мере, в Linux) была бы:
/bin/sh -c "gcc --version" gcc --version
Поскольку это установило бы командную строку из котируемых параметров , и успешно передайте другие параметры.
Из раздела sh
man-страницы для -c
:
blockquote>
Read commands from the command_string operand instead of from the standard input. Special parameter 0 will be set from the command_name operand and the positional parameters ($1, $2, etc.) set from the remaining argument operands.
Этот патч довольно просто выполняет трюк:
--- subprocess.py.orig 2009-04-19 04:43:42.000000000 +0200 +++ subprocess.py 2009-08-10 13:08:48.000000000 +0200 @@ -990,7 +990,7 @@ args = list(args) if shell: - args = ["/bin/sh", "-c"] + args + args = ["/bin/sh", "-c"] + [" ".join(args)] + args if executable is None: executable = args[0]
Из источника subprocess.py:
В UNIX с оболочкой = True: если args - это строка, она указывает строку команд, выполняемую через оболочку. Если args - это последовательность, первый элемент указывает командную строку, а любые дополнительные элементы будут рассматриваться как дополнительные аргументы оболочки.
В Windows: класс Popen использует CreateProcess () для выполнения дочерней программы, которая работает на строках. Если args - это последовательность, она будет преобразована в строку, используя метод list2cmdline. Обратите внимание, что не все приложения MS Windows интерпретируют командную строку так же: List2cmdline предназначена для приложений, использующих те же правила, что и среда выполнения MS C.
blockquote>Это не отвечает на вопрос, просто объясняет, что вы видите ожидаемое поведение.
Вероятно, что «почему» в UNIX-подобных системах аргументы команды фактически передаются приложениям (с использованием семейства вызовов
exec*
) в качестве массив строк. Другими словами, вызывающий процесс решает, что входит в аргумент командной строки EACH. Если вы говорите ему использовать оболочку, вызывающий процесс на самом деле получает возможность передать только один аргумент командной строки для выполняемой оболочки: всю командную строку, которую вы хотите исполнить, исполняемое имя и аргументы, как одна строка.Но в Windows вся командная строка (согласно приведенной выше документации) передается в виде отдельной строки дочернему процессу. Если вы посмотрите на документацию API CreateProcess , вы заметите, что он ожидает, что все аргументы командной строки будут объединены вместе в большую строку (следовательно, вызов
list2cmdline
).Плюс есть тот факт, что в UNIX-подобных системах на самом деле есть оболочка, которая может делать полезные вещи, поэтому я подозреваю, что другая причина разницы в том, что в Windows,
shell=True
ничего не делает, поэтому он работает так, как вы видите. Единственный способ заставить эти две системы действовать одинаково - это просто отказаться от всех аргументов командной строки, когдаshell=True
в Windows.
cmd.exe
), но приведенный выше комментарий указывает на то, что Python фактически не использует его, когда shell = True (вместо этого он напрямую использует CreateProcess()
).
– Greg Hewgill
10 August 2009 в 06:02
Причина поведения UNIX shell=True
связана с цитированием. Когда мы пишем команду оболочки, она будет разбита на пробелы, поэтому мы должны привести некоторые аргументы:
cp "My File" "New Location"
Это приводит к проблемам, когда наши аргументы содержат кавычки, которые требует ускорения:
grep -r "\"hello\"" .
Иногда мы можем получить ужасные ситуации , где \
тоже нужно сбежать!
Конечно, реальная проблема в том, что мы пытаемся использовать строку one для указания строк multiple . При вызове системных команд большинство языков программирования избегают этого, позволяя нам в первую очередь отправлять несколько строк, следовательно:
Popen(['cp', 'My File', 'New Location'])
Popen(['grep', '-r', '"hello"'])
Иногда бывает неплохо запускать «необработанные» команды оболочки; например, если мы скопируем что-то из сценария оболочки или веб-сайта, и мы не хотим конвертировать все ужасное экранирование вручную. Вот почему существует опция shell=True
:
Popen(['cp "My File" "New Location"'], shell=True)
Popen(['grep -r "\"hello\"" .'], shell=True)
Я не знаком с Windows, поэтому я не знаю, как и почему она ведет себя по-другому.