Вызов внешней команды в Python


Как я могу вызвать внешнюю команду (как если бы я набрал ее в командной строке Unix или Windows) из сценария Python?

30 3772

30 ответов:

посмотреть модуль подпроцесс в стандартной библиотеке:

from subprocess import call
call(["ls", "-l"])

преимущество подпроцесс и система заключается в том, что он более гибкий (вы можете получить стандартный поток вывода, стандартный поток ошибок stderr, "реальный" код, улучшена обработка ошибок, и т. д...).

The официальная документация рекомендует подпроцесс модуль над альтернативной ОС.система ():

в подпроцесс модуль предоставляет более мощные средства для порождения новых процессов и получения их результатов; использование этого модуля предпочтительнее, чем использование этой функции [os.system()].

"замена старых функций на модуль подпроцесса

вот краткое описание способов вызова внешних программ и преимущества и недостатки каждого из них:

  1. os.system("some_command with args") передает команду и аргументы в оболочку вашей системы. Это хорошо, потому что вы можете запускать несколько команд одновременно таким образом и настраивать каналы и перенаправление ввода/вывода. Например:

    os.system("some_command < input_file | another_command > output_file")  
    

    однако, хотя это удобно, вы должны вручную обрабатывать экранирование символов оболочки, таких как пространства и т. д. С другой стороны, это также позволяет запускать команды, которые являются просто командами оболочки, а не фактически внешними программами. Смотрите документация.

  2. stream = os.popen("some_command with args") будет делать то же самое как os.system за исключением того, что он дает вам файлоподобный объект, который вы можете использовать для доступа к стандартному входу/выходу для этого процесса. Есть 3 других варианта popen, которые все обрабатывают ввод / вывод немного по-разному. Если вы передаете все как строку, то ваш команда передается в оболочку; если вы передаете их в виде списка, вам не нужно беспокоиться о том, чтобы избежать чего-либо. Смотрите документация.

  3. 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. Смотрите документация.

  4. The С subprocess модуль. Это в основном так же, как Popen класс и принимает все те же аргументы, но он просто ждет, пока команда завершится и даст вам код возврата. Например:

    return_code = subprocess.call("echo Hello World", shell=True)  
    

    посмотреть в документация.

  5. если вы находитесь на Python 3.5 или более поздней версии, вы можете использовать новый тег subprocess.run функция, которая очень похожа на приведенную выше, но еще более гибкая и возвращает CompletedProcess объект, когда команда завершит работу.

  6. модуль ОС также имеет все функции 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 (список всех файлов). Если вы хотите узнать больше о любой из библиотек, которые я перечислил и связал документацию для каждой из них.

источники:

это все библиотеки:

надеюсь, это будет помогите вам принять решение о том, какую библиотеку использовать:)

подпроцесс

подпроцесс позволяет вызывать внешние команды и подключать их к своим каналам ввода/вывода/ошибок (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 функции здесь документация.

это может быть так просто:

import os
cmd = "your command"
os.system(cmd)

вызов внешней команды в Python

простой, использовать subprocess.run, который возвращает

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):

  1. вы можете установить количество параллельных процессов для запуска ("слоты") с:

    ts -S <number-of-slots>

  2. установка ts не требует прав администратора. Вы можете скачать и скомпилировать его из исходного кода с помощью простого make, добавьте его на свой путь, и все готово.