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

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

30 ответов


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

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

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

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

в подпроцесс модуль предоставляет более мощные средства для нереста новых процессов и получения их результатов; использование этого модуля предпочтительнее использования этой функции [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. на 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. на С subprocess модуль. Это просто как Popen class и принимает все те же аргументы, но он просто ждет, пока команда не завершится и не даст вам код возврата. Например:

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

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

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

  6. модуль ОС также имеет все функции fork / exec/spawn, которые у вас были бы в программе на C, но я не рекомендую их использовать непосредственно.

на 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-скрипта.

классический пример из документов модуля подпроцесса:

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.стандартный вывод. А рабочим решением было следующее:--4-->

pid = subprocess.Popen([sys.executable, "longtask.py"], stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE)

Я не проверял код на других платформах и не знаю причин поведения на freebsd. Если кто знает, пожалуйста, поделитесь своими идеями. Googling при запуске фоновых процессов в Python еще не проливает свет.


Я бы рекомендовал использовать модуль подпроцесса вместо ОС.система, потому что она делает shell escaping для вас и поэтому намного безопаснее: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 используется для " операционной системы зависит функциональность." Он также может использоваться для вызова внешних команд с помощью os.system и os.popen (Примечание: существует также подпроцесс.к 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 [email protected]:.') # 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.сплит can помочь вам разобрать команду 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)

повышение при сбое беги:

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

оригинальный ответ:

я рекомендую попробовать Посланник. Это обертка для подпроцесса, который в свою очередь стремится заменить старые модули и функции. Envoy-это подпроцесс для людей.

пример использования 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, который возвращает ? Я бы попытался найти прецедент, основанный только на аргументах. Прямое использование Popen однако даст вам доступ к его методам, включая poll, 'send_signal', 'прекратить', и 'ждать'.

здесь Popen подпись, как указано в источник. Я думаю, что это наиболее точная инкапсуляция информации (в отличие от help(Popen)):

def __init__(self, args, bufsize=-1, executable=None,
             stdin=None, stdout=None, stderr=None,
             preexec_fn=None, close_fds=_PLATFORM_DEFAULT_CLOSE_FDS,
             shell=False, cwd=None, env=None, universal_newlines=False,
             startupinfo=None, creationflags=0,
             restore_signals=True, start_new_session=False,
             pass_fds=(), *, encoding=None, errors=None):

но более информативным является the Popen документация:

subprocess.Popen(args, bufsize=-1, executable=None, stdin=None,
                 stdout=None, stderr=None, preexec_fn=None, close_fds=True,
                 shell=False, cwd=None, env=None, universal_newlines=False,
                 startupinfo=None, creationflags=0, restore_signals=True,
                 start_new_session=False, pass_fds=(), *, encoding=None, errors=None)

выполнить дочернюю программу в новом процессе. В POSIX, в класс использует ОС.execvp()-подобное поведение для выполнения программы детьми. в Windows, класс использует функцию Windows CreateProcess (). Аргументы К popen следующим образом.

понимание оставшейся документации по Popen будет оставлено в качестве упражнения для читателя.


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:

#!/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 |
+--------------------------------------+------------+------+

выход печать(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, добавьте его на свой путь, и все готово.