Другие ответы здесь адекватно объясняют предостережения безопасности, которые также упоминаются в subprocess
документации. Но в дополнение к этому, издержки запуска оболочки для запуска программы, которую вы хотите запустить, часто не нужны и, безусловно, глупы в ситуациях, когда вы фактически не используете какую-либо функциональность оболочки. Более того, дополнительная скрытая сложность должна пугать вас, особенно если вы не очень хорошо знакомы с оболочкой или предоставляемыми ей службами.
Там, где взаимодействия с оболочкой нетривиальны, теперь вам требуется, чтобы читатель и сопровождающий сценария Python (который может быть вашим будущим я или не мог) понимал как Python, так и сценарий оболочки. Помните девиз Python «явное лучше, чем неявное»; даже если код Python будет несколько более сложным, чем эквивалентный (и часто очень краткий) сценарий оболочки, вам может быть лучше удалить оболочку и заменить функциональность собственными конструкциями Python. Минимизация работы, выполняемой во внешнем процессе, и сохранение контроля в собственном коде, насколько это возможно, часто является хорошей идеей просто потому, что она улучшает видимость и снижает риски нежелательных или нежелательных побочных эффектов.
Расширение подстановочных знаков, интерполяция переменных и перенаправление - все это легко заменить на собственные конструкции Python. Сложный конвейер оболочки, где части или все не могут быть разумно переписаны в Python, был бы единственной ситуацией, когда вы могли бы рассмотреть возможность использования оболочки. Вы все равно должны убедиться, что понимаете последствия для производительности и безопасности.
В тривиальном случае, чтобы избежать shell=True
, просто замените
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.
-l
передается/bin/sh
(оболочке) вместоls
программы в Unix, еслиshell=True
. Строковый аргумент должен использоватьсяshell=True
в большинстве случаев вместо списка.