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