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