Фактическое значение 'shell=True' в подпроцессе


Я вызываю разные процессы с помощью subprocess модуль. Однако, у меня есть вопрос.

в следующий код:

callProcess = subprocess.Popen(['ls', '-l'], shell=True)

и

callProcess = subprocess.Popen(['ls', '-l']) # without shell

оба работают. После прочтения документов, я узнал, что shell=True означает выполнение кода через оболочку. Таким образом, это означает, что в отсутствие, процесс непосредственно запускается.

Итак, что я должен предпочесть для моего случая - мне нужно запустить процесс и получить его результат. Какую пользу я получаю от этого вызывая его изнутри оболочки или снаружи нее.

5 173

5 ответов:

преимущество не вызова через оболочку заключается в том, что вы не вызываете " таинственную программу.'На POSIX, переменная окружения SHELL управляет тем, какой двоичный файл вызывается как " оболочка."На Windows нет потомка Bourne shell, только cmd.исполняемый.

таким образом, вызов оболочки вызывает программу по выбору пользователя и зависит от платформы. Вообще говоря, избегайте вызовов через оболочку.

вызов через оболочку позволяет расширить среду переменные и файловые глобусы в соответствии с обычным механизмом оболочки. В системах POSIX оболочка расширяет файловые глобусы до списка файлов. В Windows, файл glob (например,"*.* ") не расширяется оболочкой, так или иначе (но переменные среды в командной строке are расширено с помощью cmd.исполняемый.)

если вы думаете, что хотите расширения переменных среды и глобусы файлов, исследуйте ILS атаки 1992-ish на сетевые службы, которые выполняли вызовы подпрограмм через ракушка. Примеры включают в себя различные sendmail бэкдоры с участием ILS.

В общем, используйте shell=False.

>>> import subprocess
>>> subprocess.call('echo $HOME')
Traceback (most recent call last):
...
OSError: [Errno 2] No such file or directory
>>>
>>> subprocess.call('echo $HOME', shell=True)
/user/khong
0

установка аргумента оболочки в значение true приводит к тому, что подпроцесс порождает промежуточный процесс оболочки и говорит ему выполнить команду. Другими словами, использование промежуточной оболочки означает, что переменные, шаблоны глобусов и другие специальные функции оболочки в командной строке обрабатываются до выполнения команды. Здесь, в Примере, $HOME был обработан перед командой echo. Фактически, это случай команды с расширением оболочки, в то время как команда ls-l рассматривается как простая команда.

источник: Модуль Подпроцесс

выполнение программ через оболочку означает, что весь пользовательский ввод, передаваемый в программу, интерпретируется в соответствии с синтаксисом и семантическими правилами вызываемой оболочки. В лучшем случае это только причиняет неудобства пользователю, потому что пользователь должен соблюдать эти правила. Например, пути, содержащие специальные символы оболочки, такие как кавычки или пробелы, должны быть экранированы. В худшем случае это приводит к утечке безопасности, потому что пользователь может выполнять произвольные программы.

shell=True is иногда удобно использовать определенные функции оболочки, такие как разделение слов или расширение параметров. Однако, если такая функция требуется, используйте другие модули, которые вам даны (например,os.path.expandvars() для расширения параметра или shlex для разделения слов). Это означает больше работы, но позволяет избежать других проблем.

короче: не shell=True все средства.

пример, где все может пойти не так с Shell=True показан здесь

>>> from subprocess import call
>>> filename = input("What file would you like to display?\n")
What file would you like to display?
non_existent; rm -rf / # THIS WILL DELETE EVERYTHING IN ROOT PARTITION!!!
>>> call("cat " + filename, shell=True) # Uh-oh. This will end badly...

Проверьте документ здесь:подпроцесс.звоните()

другие ответы здесь адекватно объясняют предостережения безопасности, которые также упоминаются в subprocess документация. Но в дополнение к этому, накладные расходы на запуск оболочки для запуска программы, которую вы хотите запустить, часто не нужны и определенно глупы для ситуаций, когда вы фактически не используете какую-либо функциональность оболочки. Более того, дополнительная скрытая сложность должна вас напугать,особенно если вы не очень хорошо знакомы с оболочкой или услуг это обеспечивает.

расширение подстановочных знаков, интерполяция переменных и перенаправление-все это просто заменить собственными конструкциями Python. Сложный конвейер оболочки, где части или все не могут быть разумно переписаны в Python (специализированные внешние инструменты, возможно, с закрытым исходным кодом?) была бы одна ситуация, когда, возможно, вы могли бы рассмотреть возможность использования оболочки. Тебе все равно должно быть стыдно.

в тривиальном случае, просто заменить

subprocess.Popen("command -with -options 'like this' and\ an\ argument", shell=True)

С

subprocess.Popen(['command', '-with','-options', 'like this', 'and an argument'])

обратите внимание, что первый аргумент-это список строк для передачи в execvp(), и как цитирование строк и метасимволов оболочки с обратной косой чертой обычно не требуется (или полезно, или правильно).

в стороне, вы очень часто хотите, чтобы избежать Popen если одна из более простых оберток в subprocess пакета делает то, что вы хотите. Если у вас есть достаточно недавний Python, вы, вероятно, должны использовать subprocess.run.

  • С check=True это не удастся, если команда, которую вы выполнили не удалось.
  • С stdout=subprocess.PIPE он будет захватывать выходные данные команды.
  • несколько смутно, с universal_newlines=True он будет декодировать вывод в соответствующую строку Unicode (это просто bytes в системной кодировке иначе, на Python 3).

если нет, то для многих задач, требуется check_output для получения выходных данных из команды при проверке что это удалось, или check_call если нет выхода для сбора.

я закончу цитатой из Дэвида Корна: "легче написать портативную оболочку, чем сценарий портативной оболочки.- Даже subprocess.run('echo "$HOME"', shell=True) не переносится в Windows.