Фактический смысл «shell = True» в подпроцессе

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

В следующих кодах:

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

а также

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

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

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

  • Использование событий с matplotlib в цикле for
  • Запуск сценария bash изнутри python
  • Генерирование N равномерных случайных чисел, которые суммируются с M
  • Subprocess.call или Subprocess.Popen не могут использовать исполняемые файлы, которые находятся в PATH (Linux / Windows)
  • Как программно проверить, анимирован ли GIF-образ?
  • ошибка: непризнанная опция командной строки '-fstack-protector-strong'
  • Как запустить разные версии python в cmd
  • Удостоверение классификаторов в детекторе лица opencv
  • 5 Solutions collect form web for “Фактический смысл «shell = True» в подпроцессе”

    Преимущество не вызова через оболочку заключается в том, что вы не вызываете «тайную программу». В POSIX переменная среды SHELL контролирует, какой двоичный код вызывается как «оболочка». В Windows отсутствует потомок оболочки bourne, только cmd.exe.

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

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

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

    В заключение, используйте shell=False .

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

    shell=True иногда удобно использовать определенные функции оболочки, такие как разбиение слов или расширение параметра. Однако, если такая функция необходима, вам предоставляются другие модули (например, 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.call ()

     >>> 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 

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

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

    Другие ответы здесь адекватно объясняют предостережения безопасности, которые также упоминаются в документации к 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).

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

    Я закрою цитату из Дэвида Корна: «Легче писать переносимую оболочку, чем переносимый сценарий оболочки».

    Interesting Posts
    Python - лучший язык программирования в мире.