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

3093
голосов

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

задан freshWoWer 18 сент. '08 в 4:35
источник

46 ответов

  • 1
  • 2
2964
голосов

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

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

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

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

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

"" Замена старых функций с помощью модуля "Подпроцесс" " в документации подпроцесса может быть несколько полезных рецептов.

Официальная документация по модулю подпроцесса:

ответ дан David Cournapeau 18 сент. '08 в 4:39
источник
2226
голосов

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

  • 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, которые все обрабатывают i/o немного по-другому. Если вы передаете все как строку, ваша команда передается в оболочку; если вы передадите их в список, то вам не нужно беспокоиться о том, чтобы избежать чего-либо. Смотрите документацию.

  • Класс 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. См. документацию.

  • Функция call из модуля subprocess. Это в основном так же, как класс Popen, и принимает все те же аргументы, но он просто ждет, пока команда не завершится, и вы получите код возврата. Например:

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

    Смотрите документацию.

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

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

Модуль subprocess должен, вероятно, быть тем, что вы используете.

Наконец, имейте в виду, что для всех методов, в которых вы передаете окончательную команду, которая будет выполняться оболочкой в ​​виде строки, и вы несете ответственность за ее удаление. Существуют серьезные последствия для безопасности, если какая-либо часть передаваемой строки не может быть полностью доверена. Например, если пользователь вводит какую-либо/любую часть строки. Если вы не уверены, используйте эти методы только с константами. Чтобы дать вам намек на последствия, рассмотрите этот код:

print subprocess.Popen("echo %s " % user_input, stdout=PIPE).stdout.read()

и представьте, что пользователь вводит "моя мама не любила меня && rm -rf/".

ответ дан Eli Courtwright 18 сент. '08 в 16:11
источник
212
голосов

Я обычно использую:

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().

ответ дан EmmEff 18 сент. '08 в 21:20
источник
126
голосов

Некоторые подсказки по отсоединению дочернего процесса от вызывающего (запуск дочернего процесса в фоновом режиме).

Предположим, вы хотите запустить длинную задачу из CGI- script, то есть дочерний процесс должен жить дольше, чем процесс выполнения CGI- script.

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

import subprocess
import sys

# some code here

pid = subprocess.Popen([sys.executable, "longtask.py"]) # call subprocess

# some more code here

Идея здесь заключается в том, что вы не хотите ждать в подпроцессе "call sub" до тех пор, пока longtask.py не будет завершен. Но неясно, что происходит после строки "еще один код здесь" из примера.

Моя целевая платформа была бесплатной, но разработка была в Windows, поэтому я сначала столкнулся с проблемой в Windows.

В окнах (win xp) родительский процесс не завершится, пока longtask.py не завершит свою работу. Это не то, что вы хотите в CGI- script. Проблема не специфична для 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- script. Некоторые эксперименты показали, что проблема, по-видимому, заключается в совместном использовании sys.stdout. И рабочим решением было следующее:

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

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

ответ дан newtover 12 февр. '10 в 13:15
источник
80
голосов

Я бы рекомендовал использовать модуль подпроцесса вместо os.system, потому что он для вас отключается, и поэтому гораздо безопаснее: http://docs.python.org/library/subprocess.html

subprocess.call(['ping', 'localhost'])
ответ дан sirwart 18 сент. '08 в 4:42
источник
67
голосов
import os
cmd = 'ls -al'
os.system(cmd)

Если вы хотите вернуть результаты команды, вы можете использовать os.popen. Тем не менее, это устарело со версии 2.6 в пользу модуля подпроцесса, который другие ответы хорошо рассмотрели.

ответ дан Alexandra Franks 18 сент. '08 в 4:37
источник
58
голосов
import os
os.system("your command")

Обратите внимание, что это опасно, так как команда не очищается. Я оставляю это для вас в Google для соответствующих документов в модулях "os" и "sys". Есть куча функций (exec *, spawn *), которые будут делать похожие вещи.

ответ дан nimish 18 сент. '08 в 4:37
источник
42
голосов

Также проверьте библиотеку Python "pexpect".

Он позволяет осуществлять интерактивное управление внешними программами/командами, даже ssh, ftp, telnet и т.д. Вы можете просто набрать что-то вроде:

child = pexpect.spawn('ftp 192.168.0.24')

child.expect('(?i)name .*: ')

child.sendline('anonymous')

child.expect('(?i)password')
ответ дан athanassis 07 окт. '10 в 10:09
источник
41
голос

Я всегда использую 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)
ответ дан Jorge E. Cardona 13 марта '12 в 3:12
источник
37
голосов

Если вам нужен вывод из команды, которую вы вызываете,
то вы можете использовать subprocess.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.

Если оболочка True, указанная команда будет выполнена через оболочку. Это может быть полезно, если вы используете Python в первую очередь для расширенного потока управления, который он предлагает для большинства системных оболочек, и по-прежнему хотят иметь удобный доступ к другим функциям оболочки, таким как оболочки, подстановочные знаки файлов, расширение переменных окружения и расширение ~ для пользователей каталог. Однако обратите внимание, что сам Python предлагает реализации многих оболочечных функций (в частности, glob, fnmatch, os.walk(), os.path.expandvars(), os.path.expanduser() и shutil).

ответ дан Facundo Casco 28 апр. '11 в 23:29
источник
37
голосов

Существует множество разных библиотек, которые позволяют вам вызывать внешние команды с помощью Python. Для каждой библиотеки я дал описание и показал пример вызова внешней команды. В качестве примера я использовал команду ls -l (список всех файлов). Если вы хотите узнать больше о любой из библиотек, которые я перечислил, и связать документацию для каждого из них.

Источники:

  

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

  

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

подпроцесс

Подпроцесс позволяет вам вызывать внешние команды и подключать их к их каналам ввода/вывода/ошибок (stdin, stdout и stderr). Subprocess - это выбор по умолчанию для запуска команд, но иногда другие модули лучше.

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 (Примечание: существует также подпроцесс .popen). os всегда будет запускать оболочку и является простой альтернативой для людей, которым это не нужно, или не знает, как использовать 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 - это библиотека для "script -подобных" программ 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. Он позволяет выполнять локальные и удаленные команды оболочки. Ткань является простой альтернативой для запуска команд в защищенной оболочке (SSH)

fabric.operations.local('ls -l') # Run command as normal
fabric.operations.local('ls -l', capture = True) # Run command and receive output

посланник

envoy известен как "подпроцесс для людей". Он используется как удобная обложка вокруг модуля subprocess.

r = envoy.run("ls -l") # Run command
r.std_out # get output

Команды

commands содержит функции-обертки для os.popen, но он был удален из Python 3, поскольку subprocess является лучшей альтернативой.

Редактирование было основано на комментарии Дж. Ф. Себастьяна.

ответ дан Tom Fuller 29 окт. '16 в 17:02
источник
35
голосов

Вот как я запускаю свои команды. Этот код содержит все, что вам нужно.

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()
ответ дан Usman Khan 28 окт. '12 в 8:14
источник
31
голос

Со стандартной библиотекой

Используйте модуль подпроцесса:

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

Это рекомендуемый стандартный способ. Однако более сложные задачи (трубы, выходные данные, ввод и т.д.) Могут быть утомительными для создания и записи.

Примечание. shlex.split может помочь вам разобрать команду для call и других subprocess функций в случае, если вы не хотите (или можете 't!) предоставить их в виде списков:

import shlex
from subprocess import call
call(shlex.split('ls -l'))

С внешними зависимостями

Если вы не против внешних зависимостей, используйте plumbum:

from plumbum.cmd import ifconfig
print(ifconfig['wlan0']())

Это лучшая оболочка subprocess. Это кросс-платформенный, то есть он работает как в Windows, так и в Unix-подобных системах. Установите pip install plumbum.

Другая популярная библиотека sh:

from sh import ifconfig
print(ifconfig('wlan0'))

Однако sh опустила поддержку Windows, поэтому она не такая потрясающая, как раньше. Установите pip install sh.

ответ дан Honza Javorek 11 апр. '13 в 20:17
источник
29
голосов

Update:

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'>]
ответ дан Joe 15 нояб. '12 в 20:13
источник
25
голосов

Без вывода результата:

import os
os.system("your command here")

С выходом результата:

import commands
commands.getoutput("your command here")
or
commands.getstatusoutput("your command here")
ответ дан Zuckonit 18 апр. '13 в 4:09
источник
19
голосов

Существует также 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
ответ дан stuckintheshuck 10 окт. '14 в 20:41
источник
17
голосов

os.system ОК, но вроде датировано. Это также не очень безопасно. Вместо этого попробуйте subprocess. subprocess не вызывает sh напрямую и поэтому более безопасен, чем os.system.

Получить дополнительную информацию здесь.

ответ дан Martin W 18 сент. '08 в 4:53
источник
17
голосов

https://docs.python.org/2/library/subprocess.html

... или для очень простой команды:

import os
os.system('cat testfile')
ответ дан Ben Hoffstein 18 сент. '08 в 4:43
источник
15
голосов

Использование:

import os

cmd = 'ls -al'

os.system(cmd)

os - этот модуль предоставляет переносимый способ использования функциональных возможностей, зависящих от операционной системы.

Для более os функций здесь является документация.

ответ дан Priyankara 29 июня '15 в 14:34
источник
13
голосов

Здесь есть другая разница, которая не упоминается выше.

subprocess.Popen выполняет как подпроцесс. В моем случае мне нужно выполнить файл, который должен связываться с другой программой.

Я пробовал подпроцесс, выполнение было успешным. Однако не smog comm. все нормально, когда я запускаю оба из терминала.

Еще одно: (ПРИМЕЧАНИЕ: kwrite ведет себя отличным от других приложений. Если вы попробуете ниже с результатами firefox, не будет одинаковым)

Если вы попробуете os.system("kwrite"), поток программы замерзает, пока пользователь не закроет kwrite. Чтобы преодолеть это, я попытался вместо этого os.system(konsole -e kwrite). Эта программа продолжилась, но kwrite стал подпроцессом консоли.

Кто-нибудь запускает kwrite, не являющийся подпроцессом (т.е. на мониторе системы он должен появляться на крайнем левом краю дерева)

ответ дан Atinc Delican 09 янв. '10 в 0:11
источник
13
голосов

subprocess.check_call удобно, если вы не хотите проверять возвращаемые значения. Он генерирует исключение при любой ошибке.

ответ дан cdunn2001 18 янв. '11 в 22:21
источник
12
голосов

os.system не позволяет сохранять результаты, поэтому, если вы хотите сохранить результаты в каком-то списке или что-то subprocess.call работает.

ответ дан Saurabh Bangad 12 июня '12 в 1:28
источник
12
голосов

Я обычно использую subprocess вместе с 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)
ответ дан Emil Stenström 30 апр. '14 в 17:37
источник
11
голосов

os.system был заменен модулем subprocess. Вместо этого используйте подпрограмму.

ответ дан William Keller 02 дек. '17 в 21:47
10
голосов

Бесстыдный плагин, я написал для этого библиотеку: P https://github.com/houqp/shell.py

В настоящее время это оболочка для popen и shlex. Он также поддерживает команды конвейеров, чтобы упростить цепочку команд в Python. Таким образом, вы можете делать такие вещи, как:

ex('echo hello shell.py') | "awk '{print $2}'"
ответ дан houqp 01 мая '14 в 23:49
источник
10
голосов

Вы можете использовать Popen, а затем вы можете проверить статус процедуры:

from subprocess import Popen

proc = Popen(['ls', '-l'])
if proc.poll() is None:
    proc.kill()

Отметьте subprocess.Popen.

ответ дан admire 16 июля '12 в 18:16
источник
8
голосов

Вот мои два цента: на мой взгляд, это лучшая практика при работе с внешними командами...

Это возвращаемые значения из метода execute...

pass, stdout, stderr = execute(["ls","-la"],"/home/user/desktop")

Это метод выполнения...

def execute(cmdArray,workingDir):

    stdout = ''
    stderr = ''

    try:
        try:
            process = subprocess.Popen(cmdArray,cwd=workingDir, stdout=subprocess.PIPE, stderr=subprocess.PIPE, bufsize=1)
        except OSError:
            return [False, '', 'ERROR : command(' + ' '.join(cmdArray) + ') could not get executed!']

        for line in iter(process.stdout.readline, b''):

            try:
                echoLine = line.decode("utf-8")
            except:
                echoLine = str(line)

            stdout += echoLine

        for line in iter(process.stderr.readline, b''):

            try:
                echoLine = line.decode("utf-8")
            except:
                echoLine = str(line)

            stderr += echoLine

    except (KeyboardInterrupt,SystemExit) as err:
        return [False,'',str(err)]

    process.stdout.close()

    returnCode = process.wait()
    if returnCode != 0 or stderr != '':
        return [False, stdout, stderr]
    else:
        return [True, stdout, stderr]
ответ дан urosjarc 14 окт. '15 в 10:12
источник
8
голосов

Чтобы получить идентификатор сети из нейтрона openstack:

#!/usr/bin/python
import os
netid= "nova net-list | awk '/ External / { print $2 }'"
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
ответ дан IRSHAD 20 июля '16 в 12:50
источник
8
голосов

В Windows вы можете просто импортировать модуль subprocess и запустить внешние команды, вызвав subprocess.Popen(), subprocess.Popen().communicate() и subprocess.Popen().wait(), как показано ниже:

# Python script to run a command line
import subprocess

def execute(cmd):
    """
        Purpose  : To execute a command and return exit status
        Argument : cmd - command to execute
        Return   : exit_code
    """
    process = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    (result, error) = process.communicate()

    rc = process.wait()

    if rc != 0:
        print "Error: failed to execute command:", cmd
        print error
    return result
# def

command = "tasklist | grep python"
print "This process detail: \n", execute(command)

Вывод:

This process detail:
python.exe                     604 RDP-Tcp#0                  4      5,660 K
ответ дан Swadhikar C 17 июня '16 в 12:14
источник
8
голосов

В Linux, если вы хотите вызвать внешнюю команду, которая будет выполняться независимо (будет работать после завершения python script), вы можете использовать простую очередь как диспетчер задач или at команда

Пример с диспетчером очереди задач:

import os
os.system('ts <your-command>')

Заметки о диспетчере очереди задач (ts):

  • Вы можете установить количество одновременных процессов, которые будут выполняться ( "слоты" ) с помощью:

    ts -S <number-of-slots>

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

ответ дан yuval 27 нояб. '16 в 3:15
источник
  • 1
  • 2

Другие вопросы по меткам