Как вы вызываете внешнюю команду (как будто я набрал ее в оболочке Unix или командной строке Windows) из скрипта Python?
4887
Посмотрите на модуль подпроцесса в стандартной библиотеке:
import subprocess
subprocess.run(["ls", "-l"])
Преимущество subprocess
против прогноза в system
том , что она является более гибкой (вы можете получить stdout
, stderr
, «реальный» код состояния, лучше обработка ошибок, и т.д ...).
Официальная документация рекомендует subprocess
модуль над альтернативой os.system()
:
subprocess
Модуль предоставляет более мощные средства для порождения новых процессов и получения их результатов; использование этого модуля предпочтительнее, чем использование этой функции [os.system()
].
В замене старых функций с помощью подпроцесса модуля раздел в subprocess
документации может иметь некоторые полезные рецепты.
Для версий Python до 3.5 используйте call
:
import subprocess
subprocess.call(["ls", "-l"])
echo $PATH
с помощьюcall(["echo", "$PATH"])
, но он просто повторил буквальную строку$PATH
вместо какой-либо замены. Я знаю, что могу получить переменную среды PATH, но мне интересно, есть ли простой способ заставить команду вести себя точно так же, как если бы я выполнял ее в bash.shell=True
это для работы.shell=True
, для этого Python поставляется с os.path.expandvars . В вашем случае вы можете написать:os.path.expandvars("$PATH")
. @SethMMorton, пожалуйста, пересмотрите свой комментарий -> Почему бы не использовать shell = Truefor
цикле, как мне это сделать без блокировки моего скрипта на python? Меня не волнует вывод команды, я просто хочу запустить их много.subprocess
когдаshell=False
, а затем используйтеshlex.split
для простого способа сделать это docs.python.org/2/library/shlex.html#shlex.splitВот краткое изложение способов вызова внешних программ, а также преимуществ и недостатков каждой из них:
os.system("some_command with args")
передает команду и аргументы в оболочку вашей системы. Это хорошо, потому что вы можете таким образом запускать несколько команд одновременно и настраивать каналы и перенаправление ввода / вывода. Например:Однако, хотя это удобно, вы должны вручную обрабатывать экранирование символов оболочки, таких как пробелы и т. Д. С другой стороны, это также позволяет запускать команды, которые являются просто командами оболочки, а не внешними программами. Смотрите документацию .
stream = os.popen("some_command with args")
будет делать то же самое,os.system
за исключением того, что он дает вам файловый объект, который вы можете использовать для доступа к стандартному вводу / выводу для этого процесса. Есть 3 других варианта popen, которые все обрабатывают ввод / вывод немного по-другому. Если вы передаете все как строку, то ваша команда передается в оболочку; если вы передаете их в виде списка, вам не нужно беспокоиться о том, чтобы избежать чего-либо. Смотрите документацию .Popen
Классsubprocess
модуля. Это задумано как замена,os.popen
но имеет обратную сторону, потому что является немного более сложным из-за того, что оно настолько всеобъемлющее. Например, вы бы сказали:вместо:
но хорошо иметь все опции в одном унифицированном классе вместо 4-х различных попсовых функций. Смотрите документацию .
call
Функция отsubprocess
модуля. Это в основном так же, какPopen
класс и принимает все те же аргументы, но он просто ждет, пока команда завершится, и даст вам код возврата. Например:Смотрите документацию .
Если вы используете Python 3.5 или более позднюю версию, вы можете использовать новую
subprocess.run
функцию, которая очень похожа на описанную выше, но еще более гибкая и возвращаетCompletedProcess
объект после завершения выполнения команды.Модуль os также имеет все функции fork / exec / spawn, которые вы имели бы в программе на C, но я не рекомендую использовать их напрямую.
subprocess
Модуль должен , вероятно, что вы используете.Наконец, имейте в виду, что для всех методов, в которых вы передаете последнюю команду для выполнения оболочкой в виде строки, вы несете ответственность за ее исключение. Существуют серьезные последствия для безопасности, если любой части передаваемой вами строки нельзя полностью доверять. Например, если пользователь вводит некоторую / любую часть строки. Если вы не уверены, используйте эти методы только с константами. Чтобы дать вам подсказку о последствиях, рассмотрите этот код:
и представьте, что пользователь вводит что-то "моя мама не любит меня && rm -rf /", что может стереть всю файловую систему.
источник
open
.subprocess.run()
. docs.python.org/3.5/library/subprocess.html#subprocess.runsubprocess.run(..)
что именно означает «Это не захватывает stdout или stderr по умолчанию». означают? А как насчетsubprocess.check_output(..)
STDERR?echo
перед строкой переданоPopen
? Так что полная команда будетecho my mama didnt love me && rm -rf /
.subprocess.run()
его старшие братьяsubprocess.check_call()
и сестры и соавт. Для случаев, когда этого недостаточно, смsubprocess.Popen()
.os.popen()
возможно, вообще не следует упоминать или даже после "взломать свой собственный код fork / exec / spawn".Типичная реализация:
Вы можете делать все, что вы хотите с
stdout
данными в канале. На самом деле, вы можете просто пропустить эти параметры (stdout=
иstderr=
), и он будет вести себя какos.system()
.источник
.readlines()
читает все строки одновременно, т. е. блокируется до выхода из подпроцесса (закрывает свой конец канала). Чтобы читать в режиме реального времени (если нет проблем с буферизацией), вы можете:for line in iter(p.stdout.readline, ''): print line,
p.stdout.readline()
(примечание: нетs
в конце) не увидит никаких данных, пока дочерний процесс не заполнит свой буфер Если ребенок не производит много данных, то вывод не будет в реальном времени. Смотрите вторую причину в вопросе: почему бы просто не использовать канал (popen ())? , В этом ответе приведены некоторые обходные пути (pexpect, pty, stdbuf)Popen
для простых задач. Это также излишне указываетshell=True
. Попробуйте один изsubprocess.run()
ответов.Некоторые советы по отсоединению дочернего процесса от вызывающего (запуск дочернего процесса в фоновом режиме).
Предположим, вы хотите запустить длинную задачу из CGI-скрипта. То есть дочерний процесс должен жить дольше, чем процесс выполнения сценария CGI.
Классический пример из документации модуля подпроцесса:
Идея заключается в том, что вы не хотите ждать в строке 'call subprocess', пока longtask.py не будет завершен. Но не ясно, что происходит после строки «еще немного кода здесь» из примера.
Моей целевой платформой была FreeBSD, но разработка велась на Windows, поэтому я сначала столкнулся с проблемой на Windows.
В Windows (Windows XP) родительский процесс не завершится, пока longtask.py не завершит свою работу. Это не то, что вы хотите в CGI-скрипте. Проблема не является специфичной для Python; в сообществе PHP проблемы одинаковы.
Решением является передача флага создания процесса DETACHED_PROCESS в базовую функцию CreateProcess в Windows API. Если вы установили pywin32, вы можете импортировать флаг из модуля win32process, в противном случае вы должны определить его самостоятельно:
/ * UPD 2015.10.27 @eryksun в комментарии ниже отмечает, что семантически правильный флаг - CREATE_NEW_CONSOLE (0x00000010) * /
Во FreeBSD у нас есть другая проблема: когда родительский процесс завершается, он также завершает дочерние процессы. И это не то, что вы хотите в CGI-скрипте. Некоторые эксперименты показали, что проблема заключается в том, чтобы поделиться sys.stdout. И рабочим решением было следующее:
Я не проверял код на других платформах и не знаю причин поведения во FreeBSD. Если кто-то знает, пожалуйста, поделитесь своими идеями. Поиск в Google фоновых процессов в Python пока не проливает свет.
источник
DETACHED_PROCESS
вcreationflags
избегаешь этого пути предотвращения ребенка от наследования или создания консоли. Если вы вместо этого хотите новую консоль, используйтеCREATE_NEW_CONSOLE
(0x00000010).os.devnull
потому , что некоторые консольные программы завершают работу с ошибкой в противном случае. Создайте новую консоль, когда вы хотите, чтобы дочерний процесс взаимодействовал с пользователем одновременно с родительским процессом. Было бы странно пытаться сделать оба в одном окне.Обратите внимание, что это опасно, поскольку команда не очищена. Я оставляю это на ваше усмотрение в Google для получения соответствующей документации по модулям 'os' и 'sys'. Существует множество функций (exec * и spawn *), которые будут выполнять похожие действия.
источник
subprocess
быть несколько более универсальным и портативным решением. Выполнение внешних команд, конечно, по своей природе непереносимо (необходимо убедиться, что команда доступна для каждой архитектуры, которую необходимо поддерживать), а передача пользовательского ввода в качестве внешней команды небезопасна.Я бы порекомендовал использовать модуль подпроцесса вместо os.system, потому что он делает экранирование для вас и поэтому намного безопаснее.
источник
subprocess
когдаshell=False
, а затем используйтеshlex.split
для простого способа сделать это docs.python.org/2/library/shlex.html#shlex.split ( это рекомендуемый путь в соответствии с docs docs.python.org/2/library/subprocess.html#popen-constructor )Если вы хотите вернуть результаты команды, вы можете использовать
os.popen
. Тем не менее, это не рекомендуется с версии 2.6 в пользу модуля подпроцесса , который хорошо освещены в других ответах.источник
Есть много разных библиотек, которые позволяют вам вызывать внешние команды с Python. Для каждой библиотеки я дал описание и показал пример вызова внешней команды. Команда, которую я использовал в качестве примера:
ls -l
(список всех файлов). Если вы хотите узнать больше о любой из библиотек, которые я перечислил, и связал документацию для каждой из них.Надеюсь, это поможет вам принять решение о том, какую библиотеку использовать :)
Подпроцесс позволяет вам вызывать внешние команды и подключать их к их каналам ввода / вывода / ошибок (stdin, stdout и stderr). Подпроцесс является выбором по умолчанию для запуска команд, но иногда лучше использовать другие модули.
ОС используется для «функциональной зависимости операционной системы». Его также можно использовать для вызова внешних команд с помощью
os.system
иos.popen
(Примечание. Существует также subprocess.popen). os всегда запускает оболочку и является простой альтернативой для людей, которые не нуждаются или не знают, как использоватьsubprocess.run
.sh - это интерфейс подпроцесса, который позволяет вам вызывать программы, как если бы они были функциями. Это полезно, если вы хотите выполнить команду несколько раз.
plumbum - это библиотека для скриптовых программ на Python. Вы можете вызывать такие программы, как функции, как в
sh
. Plumbum полезен, если вы хотите запустить конвейер без оболочки.pexpect позволяет создавать дочерние приложения, управлять ими и находить шаблоны в их выходных данных. Это лучшая альтернатива подпроцессу для команд, которые ожидают tty в Unix.
Fabric - это библиотека Python 2.5 и 2.7. Это позволяет вам выполнять локальные и удаленные команды оболочки. Fabric - простая альтернатива для запуска команд в защищенной оболочке (SSH)
Посланник известен как «подпроцесс для людей». Он используется как удобная обертка вокруг
subprocess
модуля.commands
содержит функции-обертки дляos.popen
, но он был удален из Python 3, посколькуsubprocess
является лучшей альтернативой.Редактирование было основано на комментарии Дж. Ф. Себастьяна.
источник
Я всегда использую
fabric
для этого такие вещи, как:Но, похоже, это хороший инструмент:
sh
(интерфейс подпроцесса Python) .Посмотрите на пример:
источник
Проверьте также библиотеку Python "pexpect".
Он позволяет интерактивно управлять внешними программами / командами, даже ssh, ftp, telnet и т. Д. Вы можете просто напечатать что-то вроде:
источник
Со стандартной библиотекой
Используйте модуль подпроцесса (Python 3):
Это рекомендуемый стандартный способ. Тем не менее, более сложные задачи (каналы, вывод, ввод и т. Д.) Могут быть трудоемкими для создания и записи.
Примечание по версии Python: если вы все еще используете Python 2, subprocess.call работает аналогичным образом.
ProTip: shlex.split может помочь вам разобрать команду для
run
,call
и другиеsubprocess
функции , в случае , если вы не хотите (или не можете!) Предоставлять их в виде списков:С внешними зависимостями
Если вы не против внешних зависимостей, используйте plumbum :
Это лучшая
subprocess
обертка. Он кроссплатформенный, то есть работает как в Windows, так и в Unix-подобных системах. Установить с помощьюpip install plumbum
.Другая популярная библиотека - это sh :
Тем не менее,
sh
отказались от поддержки Windows, так что это не так круто, как раньше. Установить с помощьюpip install sh
.источник
Если вам нужен вывод команды, которую вы вызываете, вы можете использовать subprocess.check_output (Python 2.7+).
Также обратите внимание на параметр оболочки .
источник
check_output
требуется список, а не строка. Если вы не полагаетесь на пробелы в кавычках, чтобы сделать ваш вызов действительным, самый простой и читаемый способ сделать этоsubprocess.check_output("ls -l /dev/null".split())
.Вот как я выполняю свои команды. Этот код имеет все, что вам нужно в значительной степени
источник
Обновить:
subprocess.run
это рекомендуемый подход с Python 3.5, если ваш код не должен поддерживать совместимость с более ранними версиями Python. Он более последовательный и предлагает аналогичную простоту использования, как Envoy. (Трубопровод не так прост, хотя. См. Этот вопрос, как .)Вот несколько примеров из документации .
Запустите процесс:
Поднять на неудачный забег:
Захват вывода:
Оригинальный ответ:
Я рекомендую попробовать посланника . Это оболочка для подпроцесса, который, в свою очередь, призван заменить старые модули и функции. Посланник - это подпроцесс для людей.
Пример использования из README :
Трубы вокруг тоже:
источник
Используйте подпроцесс .
... или для очень простой команды:
источник
os.system
в порядке, но отчасти устаревший. Это также не очень безопасно. Вместо этого попробуйтеsubprocess
.subprocess
не вызывает sh напрямую и поэтому более безопасен, чемos.system
.Получите больше информации здесь .
источник
subprocess
он не устраняет все проблемы с безопасностью и имеет некоторые собственные неприятные проблемы.Простое использование
subprocess.run
, которое возвращаетCompletedProcess
объект:Почему?
Начиная с Python 3.5, документация рекомендует subprocess.run :
Вот пример простейшего возможного использования - и он делает именно так, как просили:
run
ожидает успешного завершения команды, затем возвращаетCompletedProcess
объект. Вместо этого он может поднятьTimeoutExpired
(если вы дадите емуtimeout=
аргумент) илиCalledProcessError
(если он потерпит неудачу и вы пройдетеcheck=True
).Как вы могли бы понять из приведенного выше примера, stdout и stderr по умолчанию передаются на ваш собственный stdout и stderr.
Мы можем проверить возвращенный объект и увидеть заданную команду и код возврата:
Захват вывода
Если вы хотите захватить вывод, вы можете перейти
subprocess.PIPE
к соответствующемуstderr
илиstdout
:(Мне кажется интересным и немного нелогичным, что информация о версии помещается в stderr вместо stdout.)
Передайте список команд
Можно легко перейти от предоставления командной строки вручную (как предлагает вопрос) к предоставлению строки, созданной программным способом. Не создавайте строки программно. Это потенциальная проблема безопасности. Лучше предположить, что вы не доверяете вводу.
Обратите внимание, только
args
должны быть переданы позиционно.Полная подпись
Вот фактическая подпись в источнике и как показано
help(run)
:Объекты
popenargs
иkwargs
передаютсяPopen
конструктору.input
может быть строкой байтов (или Unicode, если указать кодировку илиuniversal_newlines=True
), которая будет передана в стандартный поток подпроцесса.Документация описывает
timeout=
иcheck=True
лучше, чем я мог:и этот пример
check=True
лучше, чем я мог придумать:Расширенная подпись
Вот расширенная подпись, как указано в документации:
Обратите внимание, что это означает, что только список аргументов должен передаваться позиционно. Поэтому передайте оставшиеся аргументы в качестве аргументов ключевых слов.
Popen
Когда использовать
Popen
вместо? Я бы изо всех сил пытался найти вариант использования, основанный только на аргументах. Однако прямое использованиеPopen
даст вам доступ к его методам, включаяpoll
«send_signal», «terminate» и «wait».Вот
Popen
подпись, приведенная в источнике . Я думаю, что это наиболее точная инкапсуляция информации (в отличие отhelp(Popen)
):Но более информативной является документация :
Popen
Понимание оставшейся документации
Popen
будет оставлено читателю в качестве упражнения.источник
shell=True
или (еще лучше) передать команду в виде списка.Есть также Plumbum
источник
Использование:
OS - этот модуль предоставляет портативный способ использования функциональных возможностей, зависящих от операционной системы.
Для большего количества
os
функций, вот документация.источник
Это может быть так просто:
источник
os.system
явно рекомендует избегать его в пользуsubprocess
.Мне очень нравится shell_command за его простоту. Он построен поверх модуля подпроцесса.
Вот пример из документации:
источник
Здесь есть еще одно отличие, которое не упоминалось ранее.
subprocess.Popen
выполняет <команду> как подпроцесс. В моем случае мне нужно выполнить файл <a>, который должен взаимодействовать с другой программой, <b>.Я попробовал подпроцесс, и выполнение прошло успешно. Однако <b> не смог связаться с <a>. Все нормально, когда я запускаю оба из терминала.
Еще одно: (ПРИМЕЧАНИЕ: kwrite ведет себя не так, как другие приложения. Если вы попробуете описанное ниже с Firefox, результаты не будут такими же.)
Если вы попытаетесь
os.system("kwrite")
, поток программы зависнет, пока пользователь не закроет kwrite. Чтобы преодолеть это, я попытался вместо этогоos.system(konsole -e kwrite)
. На этот раз программа продолжала работать, но kwrite стал подпроцессом консоли.Любой, кто запускает kwrite, не является подпроцессом (т. Е. В системном мониторе он должен отображаться у самого левого края дерева).
источник
os.system
не позволяет вам сохранять результаты, поэтому, если вы хотите сохранить результаты в каком-то списке или что-то,subprocess.call
работает.источник
subprocess.check_call
Это удобно, если вы не хотите проверять возвращаемые значения. Выдает исключение при любой ошибке.источник
Я склонен использовать подпроцесс вместе с shlex (для обработки экранирования строк в кавычках):
источник
Бесстыдный плагин, я написал для этого библиотеку: P https://github.com/houqp/shell.py
Это в основном обертка для попен и шлекс на данный момент. Он также поддерживает команды конвейеризации, так что вы можете упростить цепочку команд в Python. Так что вы можете делать такие вещи, как:
источник
В Windows вы можете просто импортировать
subprocess
модуль и запускать внешние команды по телефонуsubprocess.Popen()
,subprocess.Popen().communicate()
и ,subprocess.Popen().wait()
как показано ниже:Вывод:
источник
В Linux, если вы хотите вызвать внешнюю команду, которая будет выполняться независимо (будет продолжать работать после завершения сценария python), вы можете использовать простую очередь в качестве диспетчера очереди или в команде
Пример с диспетчером задач:
Примечания о диспетчере задач (
ts
):Вы можете установить количество одновременных процессов («слотов») для запуска с помощью:
ts -S <number-of-slots>
Установка
ts
не требует прав администратора. Вы можете скачать и скомпилировать его из простого источникаmake
, добавить его в свой путь, и все готово.источник
ts
не является стандартным для любого дистрибутива, о котором я знаю, хотя указатель наat
него немного полезен. Вы должны также упомянутьbatch
. Как и везде, вos.system()
рекомендации, вероятно, следует хотя бы упомянуть, что онаsubprocess
является рекомендуемой заменой.Вы можете использовать Popen, а затем вы можете проверить статус процедуры:
Проверьте подпроцесс . Открыть .
источник
Чтобы получить идентификатор сети из OpenStack Neutron :
Вывод nova net-list
Вывод печати (networkId)
источник
os.popen()
в 2016 году. Сценарий Awk может быть легко заменен собственным кодом Python.