Вызов внешней команды в Python
Как я могу вызвать внешнюю команду (как если бы я набрал ее в командной строке Unix или Windows) из сценария Python?
30 ответов:
посмотреть модуль подпроцесс в стандартной библиотеке:
from subprocess import call call(["ls", "-l"])
преимущество подпроцесс и система заключается в том, что он более гибкий (вы можете получить стандартный поток вывода, стандартный поток ошибок stderr, "реальный" код, улучшена обработка ошибок, и т. д...).
The официальная документация рекомендует подпроцесс модуль над альтернативной ОС.система ():
в подпроцесс модуль предоставляет более мощные средства для порождения новых процессов и получения их результатов; использование этого модуля предпочтительнее, чем использование этой функции [
os.system()
].
вот краткое описание способов вызова внешних программ и преимущества и недостатки каждого из них:
os.system("some_command with args")
передает команду и аргументы в оболочку вашей системы. Это хорошо, потому что вы можете запускать несколько команд одновременно таким образом и настраивать каналы и перенаправление ввода/вывода. Например:os.system("some_command < input_file | another_command > output_file")
однако, хотя это удобно, вы должны вручную обрабатывать экранирование символов оболочки, таких как пространства и т. д. С другой стороны, это также позволяет запускать команды, которые являются просто командами оболочки, а не фактически внешними программами. Смотрите документация.
stream = os.popen("some_command with args")
будет делать то же самое какos.system
за исключением того, что он дает вам файлоподобный объект, который вы можете использовать для доступа к стандартному входу/выходу для этого процесса. Есть 3 других варианта popen, которые все обрабатывают ввод / вывод немного по-разному. Если вы передаете все как строку, то ваш команда передается в оболочку; если вы передаете их в виде списка, вам не нужно беспокоиться о том, чтобы избежать чего-либо. Смотрите документация.The
Popen
классsubprocess
модуль. Это предназначено в качестве замены дляos.popen
но имеет обратную сторону быть немного более сложным в силу того, чтобы быть настолько всеобъемлющим. Например, вы скажете:print subprocess.Popen("echo Hello World", shell=True, stdout=subprocess.PIPE).stdout.read()
вместо:
print os.popen("echo Hello World").read()
но это приятно все опции там в одном унифицированном классе вместо 4 различных функций popen. Смотрите документация.
The С
subprocess
модуль. Это в основном так же, какPopen
класс и принимает все те же аргументы, но он просто ждет, пока команда завершится и даст вам код возврата. Например:return_code = subprocess.call("echo Hello World", shell=True)
посмотреть в документация.
если вы находитесь на Python 3.5 или более поздней версии, вы можете использовать новый тег
subprocess.run
функция, которая очень похожа на приведенную выше, но еще более гибкая и возвращаетCompletedProcess
объект, когда команда завершит работу.модуль ОС также имеет все функции fork / exec / spawn, которые у вас есть в программе на C, но я не рекомендую их использовать непосредственно.
The
subprocess
модуль, вероятно, должен быть тем, что вы используете.наконец, обратите внимание, что для всех методов, где вы передаете последнюю команду, которая будет выполняться оболочкой в виде строки, и вы несете ответственность за ее экранирование. есть серьезные последствия для безопасности если какая-либо часть строки, которую вы пройти не можете полностью доверять. Например, если пользователь вводит некоторую / любую часть строки. Если вы не уверены, используйте только эти методы с константами. Чтобы дать вам подсказку о последствиях рассмотрим этот код:
print subprocess.Popen("echo %s " % user_input, stdout=PIPE).stdout.read()
и представьте, что пользователь вводит "моя мама не любила меня & & rm-rf /".
Я обычно использовать:
import subprocess p = subprocess.Popen('ls', shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) for line in p.stdout.readlines(): print line, retval = p.wait()
вы можете делать то, что вы хотите с
stdout
данные в трубу. На самом деле, вы можете просто опустить эти параметры (stdout=
иstderr=
) и он будет вести себя какos.system()
.
некоторые подсказки по отсоединению дочернего процесса от вызывающего (запуск дочернего процесса в фоновом режиме).
Предположим, вы хотите запустить длинную задачу из CGI-скрипта, то есть дочерний процесс должен жить дольше, чем процесс выполнения CGI-скрипта.
классический пример из подпроцесса модуля docs является:
import subprocess import sys # some code here pid = subprocess.Popen([sys.executable, "longtask.py"]) # call subprocess # some more code here
идея здесь заключается в том, что вы не хотите ждать в строке "вызов подпроцесса", пока longtask.py все кончено. Но это не ясно, что происходит после строки "еще немного кода здесь" из примера.
моя целевая платформа была freebsd, но разработка была на windows, поэтому я столкнулся с проблемой на windows в первую очередь.
в windows (win xp) родительский процесс не завершится до тех пор, пока longtask.py закончил свою работу. Это не то, что вы хотите в CGI-скрипт. Проблема не специфична для Python, в сообществе PHP проблемы одинаковы.
решение пройти DETACHED_PROCESS Флаг Создания Процесса к базовой функции CreateProcess в win API. Если вы установили pywin32, вы можете импортировать флаг из модуля win32process, в противном случае вы должны определить его самостоятельно:
DETACHED_PROCESS = 0x00000008 pid = subprocess.Popen([sys.executable, "longtask.py"], creationflags=DETACHED_PROCESS).pid
/* UPD 2015.10.27 @eryksun в комментарии ниже отмечает, что семантически правильный флаг CREATE_NEW_CONSOLE (0x00000010)*/
на freebsd у нас есть еще одна проблема: когда родительский процесс законченный, он также заканчивает дочерние процессы. И это не то, что вы хотите в CGI-скрипт либо. Некоторые эксперименты показали, что проблема, по-видимому, заключается в совместном использовании sys.стандартный вывод. И рабочее решение было следующим:
pid = subprocess.Popen([sys.executable, "longtask.py"], stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE)
Я не проверял код на других платформах и не знаю причин своего поведения на freebsd. Если кто знает, пожалуйста, поделитесь своими идеями. Гуглить при запуске фоновых процессов в Python пока не проливает никакого света.
Я бы рекомендовал использовать модуль подпроцесса вместо ОС.система, потому что она делает оболочку побега для вас и поэтому гораздо безопаснее:http://docs.python.org/library/subprocess.html
subprocess.call(['ping', 'localhost'])
import os cmd = 'ls -al' os.system(cmd)
Если вы хотите вернуть результаты команды, вы можете использовать
os.popen
. Однако, это является устаревшим, начиная с версии 2.6 в пользу модуль подпроцесс, который другие ответы покрыли хорошо.
import os os.system("your command")
обратите внимание, что это опасно, так как команда не чистить. Я оставляю это до вас в google для соответствующей документации по модулям " os " и "sys". Есть куча функций (exec* и spawn*), которые будут делать подобные вещи.
Я всегда использую
fabric
для этого такие вещи, как:from fabric.operations import local result = local('ls', capture=True) print "Content:/n%s" % (result, )
но это, кажется, хороший инструмент:
sh
(интерфейс подпроцесса Python).посмотрите пример:
from sh import vgdisplay print vgdisplay() print vgdisplay('-v') print vgdisplay(v=True)
проверьте также библиотеку Python "pexpect".
оно позволяет для взаимодействующего управления внешних программ / команд, даже ssh, ftp, telnet, etc. Вы можете просто ввести что-то вроде:
child = pexpect.spawn('ftp 192.168.0.24') child.expect('(?i)name .*: ') child.sendline('anonymous') child.expect('(?i)password')
существует множество различных библиотек, которые позволяют вызывать внешние команды с помощью Python. Для каждой библиотеки я дал описание и показал пример вызова внешней команды. В качестве примера я использовал команду
ls -l
(список всех файлов). Если вы хотите узнать больше о любой из библиотек, которые я перечислил и связал документацию для каждой из них.источники:
- подпроцесс: https://docs.python.org/3.5/library/subprocess.html
- shlex: https://docs.python.org/3/library/shlex.html
- os:https://docs.python.org/3.5/library/os.html
- sh:https://amoffat.github.io/sh/
- plumbum:https://plumbum.readthedocs.io/en/latest/
- pexpect: https://pexpect.readthedocs.io/en/stable/
- ткань:http://www.fabfile.org/
- посланник:https://github.com/kennethreitz/envoy
- команды:https://docs.python.org/2/library/commands.html
это все библиотеки:
надеюсь, это будет помогите вам принять решение о том, какую библиотеку использовать:)
подпроцесс
подпроцесс позволяет вызывать внешние команды и подключать их к своим каналам ввода/вывода/ошибок (stdin, stdout и stderr). Подпроцесс является выбором по умолчанию для выполнения команд, но иногда другие модули лучше.
subprocess.run(["ls", "-l"]) # Run command subprocess.run(["ls", "-l"], stdout=subprocess.PIPE) # This will run the command and return any output subprocess.run(shlex.split("ls -l")) # You can also use the shlex library to split the command
os
ОС используется для " зависит от операционной системы функциональность." Он также может быть использован для вызова внешних команд с
os.system
иos.popen
(Примечание: существует также подпроцесс.попен). ОС всегда будет запускать оболочку и является простой альтернативой для людей, которые не нуждаются, или не знают, как использоватьsubprocess.run
.os.system("ls -l") # run command os.popen("ls -l").read() # This will run the command and return any output
ш
sh-это интерфейс подпроцесса, который позволяет вызывать программы, как если бы они были функциями. Это полезно, если вы хотите запустить команду несколько раз.
sh.ls("-l") # Run command normally ls_cmd = sh.Command("ls") # Save command as a variable ls_cmd() # Run command as if it were a function
plumbum
Плюмбум-это библиотека для "сценарий, как" программы на Python. Вы можете вызывать такие программы, как функции, как в
sh
. Plumbum полезен, если вы хотите запустить трубопровод без оболочки.ls_cmd = plumbum.local("ls -l") # get command ls_cmd() # run command
pexpect
pexpect позволяет создавать дочерние приложения, управлять ими и находить шаблоны в их выводе. Это лучшая альтернатива подпроцесс для команд, которые ожидают tty на Unix.
pexpect.run("ls -l") # Run command as normal child = pexpect.spawn('scp foo user@example.com:.') # Spawns child application child.expect('Password:') # When this is the output child.sendline('mypassword')
ткани
fabric-это библиотека Python 2.5 и 2.7. Он позволяет выполнять локальные и удаленные команды оболочки. Fabric-это простая альтернатива для выполнения команд в защищенной оболочке (SSH)
fabric.operations.local('ls -l') # Run command as normal fabric.operations.local('ls -l', capture = True) # Run command and receive output
посланник
Если вам нужен вывод из команды, которую вы вызываете, тогда вы можете использовать подпроцесс.check_output (Python 2.7+).
>>> subprocess.check_output(["ls", "-l", "/dev/null"]) 'crw-rw-rw- 1 root root 1, 3 Oct 18 2007 /dev/null\n'
также обратите внимание на shell
вот как я запускаю свои команды. Этот код имеет все, что вам потребуется
from subprocess import Popen, PIPE cmd = "ls -l ~/" p = Popen(cmd , shell=True, stdout=PIPE, stderr=PIPE) out, err = p.communicate() print "Return code: ", p.returncode print out.rstrip(), err.rstrip()
Со Стандартной Библиотекой
в Используйте модуль подпроцесс (Python 3):
import subprocess subprocess.run(['ls', '-l'])
это рекомендуемый стандартный способ. Однако, более сложные задачи (трубы, выход, вход, и т. д.) может быть утомительно строить и писать.
примечание по версии Python: если вы все еще используете Python 2, подпроцесс.звоните работает аналогичным образом.
ProTip:shlex.сплит может помочь вам разобрать команду
run
,call
и другиеsubprocess
функции в случае, если вы не хотите (или не можете!) предоставить их в виде списка:import shlex import subprocess subprocess.run(shlex.split('ls -l'))
С Внешними Зависимостями
если вы не возражаете против внешних зависимостей, используйте plumbum:
from plumbum.cmd import ifconfig print(ifconfig['wlan0']())
это самое лучшее
subprocess
фантик. Это кросс-платформенный, т. е. он работает как на Windows, так и на Unix-подобных системах. Установить с помощьюpip install plumbum
.другой популярная библиотека ш:
from sh import ifconfig print(ifconfig('wlan0'))
однако,
sh
прекращена поддержка Windows, так что это не так здорово, как раньше. Установить с помощьюpip install sh
.
обновление:
subprocess.run
рекомендуется начиная с Python 3.5 если ваш код не должен поддерживать совместимость с более ранними версиями Python. Он более последователен и предлагает аналогичную простоту использования в качестве посланника. (Трубопроводы не так просты, хотя. Смотрите этот вопрос как.)вот несколько примеров из документы.
запустить процесс:
>>> subprocess.run(["ls", "-l"]) # doesn't capture output CompletedProcess(args=['ls', '-l'], returncode=0)
поднять на failed беги:
>>> subprocess.run("exit 1", shell=True, check=True) Traceback (most recent call last): ... subprocess.CalledProcessError: Command 'exit 1' returned non-zero exit status 1
снять выход:
>>> subprocess.run(["ls", "-l", "/dev/null"], stdout=subprocess.PIPE) CompletedProcess(args=['ls', '-l', '/dev/null'], returncode=0, stdout=b'crw-rw-rw- 1 root root 1, 3 Jan 23 16:23 /dev/null\n')
оригинальный ответ:
я рекомендую попробовать Посланник. Это обертка для подпроцесса, который в свою очередь стремится заменить старые модули и функции. Посланник-это подпроцесс для людей.
пример использования readme:
>>> r = envoy.run('git config', data='data to pipe in', timeout=2) >>> r.status_code 129 >>> r.std_out 'usage: git config [options]' >>> r.std_err ''
трубы все вокруг тоже:
>>> r = envoy.run('uptime | pbcopy') >>> r.command 'pbcopy' >>> r.status_code 0 >>> r.history [<Response 'uptime'>]
без вывода результата:
import os os.system("your command here")
С выводом результата:
import commands commands.getoutput("your command here") or commands.getstatusoutput("your command here")
https://docs.python.org/2/library/subprocess.html
...или для очень простой команды:
import os os.system('cat testfile')
появилась Plumbum
>>> from plumbum import local >>> ls = local["ls"] >>> ls LocalCommand(<LocalPath /bin/ls>) >>> ls() u'build.py\ndist\ndocs\nLICENSE\nplumbum\nREADME.rst\nsetup.py\ntests\ntodo.txt\n' >>> notepad = local["c:\windows\notepad.exe"] >>> notepad() # Notepad window pops up u'' # Notepad window is closed by user, command returns
os.system
Это нормально, но вроде датировано. Это также не очень безопасно. Вместо этого попробуйтеsubprocess
.subprocess
не вызывает sh напрямую и поэтому более безопасен, чемos.system
.получить дополнительную информацию здесь.
использование:
import os cmd = 'ls -al' os.system(cmd)
os-этот модуль обеспечивает портативный способ использования функциональности, зависящей от операционной системы.
для
os
функции здесь документация.
subprocess.check_call
удобно, если вы не хотите проверять возвращаемые значения. Он выдает исключение при любой ошибке.
есть еще одно отличие здесь не упоминалось.
subprocess.Popen
выполняеткак подпроцесс. В моем случае мне нужно выполнить файл , который должен взаимодействовать с другой программой, . я попробовал подпроцесс, и выполнение было успешным. Однако не удалось связаться с . Все нормально, когда я запускаю из терминала.
еще один: (Примечание: kwrite ведет себя иначе, чем другие приложения. Если вы попробуйте следующие с Firefox, результаты не будут одинаковыми.)
Если вы попытаетесь
os.system("kwrite")
, поток программы зависает до тех пор, пока пользователь не закроет kwrite. Чтобы преодолеть это, я попытался вместоos.system(konsole -e kwrite)
. На этот раз программа продолжала течь, но kwrite стал подпроцессом консоли.любой запускает kwrite, не являющийся подпроцессом (т. е. в системном мониторе он должен отображаться на самом левом краю дерева).
os.system
не позволяет хранить результаты, так что если вы хотите сохранить результаты в какой-то список или что-тоsubprocess.call
строительство.
Я предпочитаю использовать подпроцесс вместе с shlex (для обработки экранирования строк в кавычках):
>>> import subprocess, shlex >>> command = 'ls -l "/your/path/with spaces/"' >>> call_params = shlex.split(command) >>> print call_params ["ls", "-l", "/your/path/with spaces/"] >>> subprocess.call(call_params)
бесстыдный плагин, я написал библиотеку для этого: P https://github.com/houqp/shell.py
это в основном обертка для popen и shlex на данный момент. Он также поддерживает команды трубопроводов, так что вы можете цепочку команд проще в Python. Так что вы можете делать такие вещи, как:
ex('echo hello shell.py') | "awk '{print }'"
вы можете использовать Popen, а затем вы можете проверить статус процедуры:
from subprocess import Popen proc = Popen(['ls', '-l']) if proc.poll() is None: proc.kill()
проверить подпроцесс.К popen.
Мне нравится shell_command для своей простоты. Он построен поверх модуля подпроцесса.
вот пример из документации:
>>> from shell_command import shell_call >>> shell_call("ls *.py") setup.py shell_command.py test_shell_command.py 0 >>> shell_call("ls -l *.py") -rw-r--r-- 1 ncoghlan ncoghlan 391 2011-12-11 12:07 setup.py -rw-r--r-- 1 ncoghlan ncoghlan 7855 2011-12-11 16:16 shell_command.py -rwxr-xr-x 1 ncoghlan ncoghlan 8463 2011-12-11 16:17 test_shell_command.py 0
чтобы получить идентификатор сети из openstack neutron:
#!/usr/bin/python import os netid= "nova net-list | awk '/ External / { print }'" temp=os.popen(netid).read() /* here temp also contains new line (\n) */ networkId=temp.rstrip() print(networkId)
выход nova net-list
+--------------------------------------+------------+------+ | ID | Label | CIDR | +--------------------------------------+------------+------+ | 431c9014-5b5d-4b51-a357-66020ffbb123 | test1 | None | | 27a74fcd-37c0-4789-9414-9531b7e3f126 | External | None | | 5a2712e9-70dc-4b0e-9281-17e02f4684c9 | management | None | | 7aa697f5-0e60-4c15-b4cc-9cb659698512 | Internal | None | +--------------------------------------+------------+------+
выход print (networkId)
27a74fcd-37c0-4789-9414-9531b7e3f126
в Linux, если вы хотите вызвать внешнюю команду, которая будет выполняться независимо (будет продолжать работать после завершения скрипта python), вы можете использовать простую очередь как диспетчер очереди заданий или at команда
пример с диспетчером очереди задач:
import os os.system('ts <your-command>')
заметки о диспетчере очереди задач (
ts
):
вы можете установить количество параллельных процессов для запуска ("слоты") с:
ts -S <number-of-slots>
установка
ts
не требует прав администратора. Вы можете скачать и скомпилировать его из исходного кода с помощью простогоmake
, добавьте его на свой путь, и все готово.