it-roy-ru.com

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

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

4038
freshWoWer

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

import subprocess
subprocess.run(["ls", "-l"])

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

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

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

Раздел " Замена старых функций модулем подпроцесса " в документации subprocess может иметь несколько полезных рецептов.

3905
David Cournapeau

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

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

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

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

  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-х различных попсовых функций. Смотрите документацию .

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

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

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

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

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

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

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

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

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

2665
Eli Courtwright

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

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

292
EmmEff

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

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

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

import subprocess
import sys

# some code here

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

# some more code here

Идея состоит в том, что вы не хотите ждать в строке 'call subprocess', пока 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.stdout. И рабочим решением было следующее:

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

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

186
newtover
import os
cmd = 'ls -al'
os.system(cmd)

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

113
Alexandra Franks

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

subprocess.call(['ping', 'localhost'])
113
sirwart
import os
os.system("your command")

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

101
nimish

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

Источники:

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

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

subprocess

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

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 полезен, если вы хотите запустить конвейер без Shell.

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

посланник

посланник известен как «подпроцесс для людей». Он используется как удобная оболочка для модуля subprocess.

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

команды

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

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

63
Tom Fuller

Я всегда использую 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)
60
Jorge E. Cardona

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

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

child = pexpect.spawn('ftp 192.168.0.24')

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

child.sendline('anonymous')

child.expect('(?i)password')
59
athanassis

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

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

53
Facundo Casco

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

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

import subprocess
subprocess.run(['ls', '-l'])

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

Примечание по версии Python: если вы все еще используете Python 2, subprocess.call работает аналогичным образом.

ProTip: shlex.split может помочь вам разобрать команду для функций 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.

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

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

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

51
Honza Javorek

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

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()
45
Usman Khan

Обновление:

subprocess.run - рекомендуемый подход начиная с Python 3.5 , если ваш код не должен поддерживать совместимость с более ранними версиями Python. Он более последовательный и предлагает такую ​​же простоту использования, как и Envoy. (Пайпинг не так прост, хотя. Смотрите этот вопрос, как .)

Вот несколько примеров из документов .

Запустите процесс:

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

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

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

Пример использования из 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'>]
42
Joe

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

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

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

import commands
commands.getoutput("your command here")
or
commands.getstatusoutput("your command here")
34
Zuckonit

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

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

import os
os.system('cat testfile')
28
Ben Hoffstein

Существует также 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
27
stuckintheshuck

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

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

27
Martin W

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

Просто используйте subprocess.run, который возвращает объект CompletedProcess:

>>> import subprocess
>>> completed_process = subprocess.run('python --version')
Python 3.6.1 :: Anaconda 4.4.0 (64-bit)
>>> completed_process
CompletedProcess(args='python --version', returncode=0)

Зачем?

Начиная с Python 3.5, документация рекомендует subprocess.run :

Рекомендуемый подход к вызову подпроцессов заключается в использовании функции run () для всех случаев использования, которые она может обработать. Для более сложных вариантов использования базовый интерфейс Popen можно использовать напрямую.

Вот пример простейшего возможного использования - и он делает именно так, как просили:

>>> import subprocess
>>> completed_process = subprocess.run('python --version')
Python 3.6.1 :: Anaconda 4.4.0 (64-bit)
>>> completed_process
CompletedProcess(args='python --version', returncode=0)

run ожидает успешного завершения команды, а затем возвращает объект CompletedProcess. Вместо этого он может вызвать TimeoutExpired (если вы передадите ему аргумент timeout=) или CalledProcessError (если произойдет сбой и вы передадите check=True).

Как вы могли бы понять из приведенного выше примера, stdout и stderr по умолчанию передаются на ваш собственный stdout и stderr.

Мы можем проверить возвращенный объект и увидеть заданную команду и код возврата:

>>> completed_process.args
'python --version'
>>> completed_process.returncode
0

Захватив вывод

Если вы хотите захватить вывод, вы можете передать subprocess.PIPE соответствующему stderr или stdout:

>>> cp = subprocess.run('python --version', 
                        stderr=subprocess.PIPE, 
                        stdout=subprocess.PIPE)
>>> cp.stderr
b'Python 3.6.1 :: Anaconda 4.4.0 (64-bit)\r\n'
>>> cp.stdout
b''

(Мне кажется интересным и слегка нелогичным, что информация о версии помещается в stderr вместо stdout.)

Передайте список команд

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

>>> import textwrap
>>> args = ['python', textwrap.__file__]
>>> cp = subprocess.run(args, stdout=subprocess.PIPE)
>>> cp.stdout
b'Hello there.\r\n  This is indented.\r\n'

Обратите внимание, только args должен быть передан позиционно.

Полная подпись

Вот фактическая подпись в источнике и как показано help(run):

def run(*popenargs, input=None, timeout=None, check=False, **kwargs):

popenargs и kwargs передаются конструктору Popen. input может быть строкой байтов (или unicode, если задана кодировка или universal_newlines=True), которая будет передана в стандартный поток подпроцесса.

Документация описывает timeout= и check=True лучше, чем я мог:

Аргумент тайм-аута передается в Popen.communicate (). Если тайм-аут истекает, дочерний процесс будет убит и ждет. Исключение TimeoutExpired будет повторно вызвано после того, как дочерний процесс получил прекращается.

Если проверка верна, и процесс завершается с ненулевым кодом выхода, Возникнет исключение CalledProcessError. Атрибуты этого исключение содержит аргументы, код выхода и stdout и stderr, если они были захвачены.

и этот пример для check=True лучше, чем тот, который я мог придумать:

>>> 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(args, *, stdin=None, input=None, stdout=None, stderr=None, 
Shell=False, cwd=None, timeout=None, check=False, encoding=None, 
errors=None)

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

Popen

Когда вместо этого использовать Popen? Я бы изо всех сил пытался найти вариант использования, основанный только на аргументах. Однако прямое использование Popen даст вам доступ к его методам, включая poll, 'send_signal', 'terminate' и 'wait'.

Вот подпись 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):

Но более информативным является документация 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 класс использует os.execvp () - подобное поведение для выполнения дочерней программы. В Windows класс использует функцию Windows CreateProcess (). Аргументы в Попен таков.

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

24
Aaron Hall

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

import os
cmd = "your command"
os.system(cmd)
23
Samadi Salahedine

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

import os

cmd = 'ls -al'

os.system(cmd)

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

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

23
Priyankara

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

19
cdunn2001

Я склонен использовать подпроцесс вместе с 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)
18
Emil Stenström

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

17
Saurabh Bangad

Здесь есть еще одно отличие, которое не упоминалось ранее.

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

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

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

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

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

17
Atinc Delican

Мне очень нравится 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
16
mdwhatcott

используйте модуль os

import os
os.system("your command")

например

import os
os.system("ifconfig")
15
abhi krishnan

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

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

ex('echo hello Shell.py') | "awk '{print $2}'"
14
houqp

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

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

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

Примечания о диспетчере задач (ts): 

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

    ts -S <number-of-slots>

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

14
Yuval Atzmon

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

from subprocess import Popen

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

Проверить подпроцесс. Открыть .

13
admire

В 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
12
Swadhikar C

Очень простой способ выполнить любую команду и получить результат обратно:

from commands import getstatusoutput

try:
    return getstatusoutput("ls -ltr")
except Exception, e:
    return None
11
Garfield

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

#!/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
11
IRSHAD

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

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

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

Это метод execute ...

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]
10
Uroš Jarc

Invoke - инструмент и библиотека для выполнения задач Python (2.7 и 3.4+). Он обеспечивает чистый API высокого уровня для запуска команд Shell

>>> from invoke import run
>>> cmd = "pip install -r requirements.txt"
>>> result = run(cmd, hide=True, warn=True)
>>> print(result.ok)
True
>>> print(result.stdout.splitlines()[-1])
Successfully installed invocations-0.13.0 pep8-1.5.7 spec-1.3.1
8
Valery Ramusik

Здесь вызывается внешняя команда и возвращается или выводится вывод команды:

Python Подпроцесс check_output хорош для

Запустите команду с аргументами и верните ее вывод в виде байтовой строки.

import subprocess
proc = subprocess.check_output('ipconfig /all')
print proc
7
Rajiv Sharma

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

import subprocess

p = subprocess.Popen("df -h", Shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()[0]
print p.split("\n")

Это дает хороший результат, с которым легче работать:

['Filesystem      Size  Used Avail Use% Mounted on',
 '/dev/sda6        32G   21G   11G  67% /',
 'none            4.0K     0  4.0K   0% /sys/fs/cgroup',
 'udev            1.9G  4.0K  1.9G   1% /dev',
 'tmpfs           387M  1.4M  386M   1% /run',
 'none            5.0M     0  5.0M   0% /run/lock',
 'none            1.9G   58M  1.9G   3% /run/shm',
 'none            100M   32K  100M   1% /run/user',
 '/dev/sda5       340G  222G  100G  69% /home',
 '']
7
David Okwii

Просто чтобы добавить к обсуждению, если вы используете консоль Python, вы можете вызывать внешние команды из IPython . Находясь в приглашении IPython, вы можете вызывать команды оболочки, используя префикс «!». Вы также можете комбинировать код Python с оболочкой и назначать вывод сценариев оболочки переменным Python.

Например:

In [9]: mylist = !ls

In [10]: mylist
Out[10]:
['file1',
 'file2',
 'file3',]
7
imagineerThat

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

Простой способ вызвать внешнюю команду - использовать os.system(...). И эта функция возвращает значение выхода команды. Но недостаток в том, что мы не получим stdout и stderr.

ret = os.system('some_cmd.sh')
if ret != 0 :
    print 'some_cmd.sh execution returned failure'

Вызов внешней команды в Python в фоновом режиме

subprocess.Popen обеспечивает большую гибкость для запуска внешней команды, чем использование os.system. Мы можем запустить команду в фоновом режиме и дождаться ее завершения. И после этого мы можем получить стандартный вывод и стандартный вывод.

proc = subprocess.Popen(["./some_cmd.sh"], stdout=subprocess.PIPE)
print 'waiting for ' + str(proc.pid)
proc.wait()
print 'some_cmd.sh execution finished'
(out, err) = proc.communicate()
print 'some_cmd.sh output : ' + out

Вызов длительной внешней команды в Python в фоновом режиме и остановка через некоторое время

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

proc = subprocess.Popen(["./some_long_run_cmd.sh"], stdout=subprocess.PIPE)
# Do something else
# Now some_long_run_cmd.sh exeuction is no longer needed, so kill it
os.system('kill -15 ' + str(proc.pid))
print 'Output : ' proc.communicate()[0]
6
rashok

Есть много разных способов запуска внешних команд в Python, , И все они имеют свои плюсы и минусы.

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

Существуют также различные способы обработки кода возврата и ошибок Возможно, вы захотите проанализировать вывод и предоставить новый ввод (в стиле ожидаем ). Или вам нужно будет перенаправить stdin, stdout и stderr для запуска в другом tty (например, при использовании screen).

Так что вам, вероятно, придется написать много оберток вокруг внешней команды. Итак, вот модуль Python, который мы написали, который может обрабатывать Почти все, что вы захотите, и если нет, он очень гибкий, поэтому вы можете легко его расширить:

https://github.com/hpcugent/vsc-base/blob/master/lib/vsc/utils/run.py

6
Jens Timmerman

Как пример (в Linux):

import subprocess
subprocess.run('mkdir test.dir', Shell=True)

Это создает test.dir в текущем каталоге . Обратите внимание, что это также работает:

import subprocess
subprocess.call('mkdir test.dir', Shell=True)

Эквивалентный код, использующий os.system:

import os
os.system('mkdir test.dir')

Лучшей практикой будет использование подпроцесса вместо os, с преимуществом .run над .call. Все, что вам нужно знать о подпроцессе, это здесь . Также обратите внимание, что всю документацию по Python можно скачать с здесь . Я скачал PDF упакованный как .Zip. Я упоминаю об этом, потому что есть хороший обзор модуля os в tutorial.pdf (стр. 81). Кроме того, это авторитетный ресурс для программистов Python.

6
user8468899

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

from subprocess import PIPE, run

command = ['echo', 'hello']
result = run(command, stdout=PIPE, stderr=PIPE, universal_newlines=True)
print(result.returncode, result.stdout, result.stderr)
5
Chiel ten Brinke

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

Он получается, если процесс выполняется с использованием метода poll () для процесса .

import subprocess,sys

def exec_long_running_proc(command, args):
    cmd = "{} {}".format(command, " ".join(str(arg) if ' ' not in arg else arg.replace(' ','\ ') for arg in args))
    print(cmd)
    process = subprocess.Popen(cmd, Shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)

    # Poll process for new output until finished
    while True:
        nextline = process.stdout.readline().decode('UTF-8')
        if nextline == '' and process.poll() is not None:
            break
        sys.stdout.write(nextline)
        sys.stdout.flush()

    output = process.communicate()[0]
    exitCode = process.returncode

    if (exitCode == 0):
        return output
    else:
        raise Exception(command, exitCode, output)

Вы можете вызвать это так:

exec_long_running_proc(command = "Hive", args=["-f", hql_path])
5
am5

Простой способ - использовать модуль os:

import os
os.system('ls')

В качестве альтернативы вы также можете использовать модуль подпроцесса

import subprocess
subprocess.check_call('ls')

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

import subprocess
r = subprocess.check_output('ls')
4
amehta

Используйте subprocess.call :

from subprocess import call

# using list
call(["echo", "Hello", "world"])

# single string argument varies across platforms so better split it
call("echo Hello world".split(" "))
4
andruso

Использование функции Popen модуля Python subprocess - это самый простой способ запуска команд Linux. При этом функция Popen.communicate() выдаст ваши команды. Например

import subprocess

..
process = subprocess.Popen(..)   # Pass command and arguments to the function
stdout, stderr = process.communicate()   # Get command output and error
..
4
Asif Hasnain

Есть много способов вызвать команду.

  • Например:

если and.exe нужны два параметра. В cmd мы можем вызвать sample.exe использовать это: and.exe 2 3 и он показывает 5 на экране.

Если мы используем скрипт Python для вызова and.exe, мы должны сделать как ...

  1. os.system(cmd,...)

    • os.system(("and.exe" + " " + "2" + " " + "3"))
  2. os.popen(cmd,...)

    • os.popen(("and.exe" + " " + "2" + " " + "3"))
  3. subprocess.Popen(cmd,...)
    • subprocess.Popen(("and.exe" + " " + "2" + " " + "3"))

Это слишком сложно, поэтому мы можем присоединиться к cmd с пробелом:

import os
cmd = " ".join(exename,parameters)
os.popen(cmd)
4
liuyip

Если вам нужно вызвать команду Shell из записной книжки Python (например, Jupyter , Zeppelin, Databricks или Google Cloud Datalab), вы можете просто использовать префикс !.

Например,

!ls -ilF
3
dportman

Я написал небольшую библиотеку, чтобы помочь с этим вариантом использования:

https://pypi.org/project/citizenshell/

Может быть установлен с помощью 

pip install citizenshell

И затем используется следующим образом:

from citizenshell import sh
assert sh("echo Hello World") == "Hello World"

Вы можете отделить stdout от stderr и извлечь код выхода следующим образом:

result = sh(">&2 echo error && echo output && exit 13")
assert result.stdout() == ["output"]
assert result.stderr() == ["error"]
assert result.exit_code() == 13

И самое интересное в том, что вам не нужно ждать завершения основной оболочки, прежде чем начинать обрабатывать вывод:

for line in sh("for i in 1 2 3 4; do echo -n 'It is '; date +%H:%M:%S; sleep 1; done", wait=False)
    print ">>>", line + "!"

будет печатать строки, как они доступны, благодаря wait = False

>>> It is 14:24:52!
>>> It is 14:24:53!
>>> It is 14:24:54!
>>> It is 14:24:55!

Дополнительные примеры можно найти по адресу https://github.com/meuter/citizenshell

3
Cédric

Существует два основных способа выполнения команд оболочки с использованием Python. Оба приведенных ниже примера показывают, как можно получить имя текущего рабочего каталога (pwd) с помощью Python. Вы можете использовать любую другую команду Unix вместо pwd

1.> 1-й метод: Можно использовать модуль os из python и функцию system () оттуда для выполнения команд оболочки в Python.

import os
os.system('pwd')

Результат:

/Users/siddharth

1.> 2-й метод: Другой способ - использовать модуль подпроцесс и функцию call ()

import subprocess
subprocess.call('pwd')

Результат:

/Users/siddharth
3
Siddharth Satpathy

Я бы порекомендовал следующий метод 'run', и он поможет нам получить STDOUT, STDERR и статус выхода в качестве словаря; Вызывающая сторона может прочитать словарь, возвращаемый методом run, чтобы узнать фактическое состояние процесса. 

  def run (cmd):
       print "+ DEBUG exec({0})".format(cmd)
       p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True, Shell=True)
       (out, err) = p.communicate()
       ret        = p.wait()
       out        = filter(None, out.split('\n'))
       err        = filter(None, err.split('\n'))
       ret        = True if ret == 0 else False
       return dict({'output': out, 'error': err, 'status': ret})
  #end
2
Viswesn

После некоторого исследования у меня есть следующий код, который работает очень хорошо для меня. Он в основном печатает как stdout, так и stderr в режиме реального времени. Надеюсь, что это помогает кому-то еще, кто нуждается в этом.

stdout_result = 1
stderr_result = 1


def stdout_thread(pipe):
    global stdout_result
    while True:
        out = pipe.stdout.read(1)
        stdout_result = pipe.poll()
        if out == '' and stdout_result is not None:
            break

        if out != '':
            sys.stdout.write(out)
            sys.stdout.flush()


def stderr_thread(pipe):
    global stderr_result
    while True:
        err = pipe.stderr.read(1)
        stderr_result = pipe.poll()
        if err == '' and stderr_result is not None:
            break

        if err != '':
            sys.stdout.write(err)
            sys.stdout.flush()


def exec_command(command, cwd=None):
    if cwd is not None:
        print '[' + ' '.join(command) + '] in ' + cwd
    else:
        print '[' + ' '.join(command) + ']'

    p = subprocess.Popen(
        command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=cwd
    )

    out_thread = threading.Thread(name='stdout_thread', target=stdout_thread, args=(p,))
    err_thread = threading.Thread(name='stderr_thread', target=stderr_thread, args=(p,))

    err_thread.start()
    out_thread.start()

    out_thread.join()
    err_thread.join()

    return stdout_result + stderr_result
2
Jake W

Я написал оболочку для обработки ошибок и перенаправления вывода и прочего.

import shlex
import psutil
import subprocess

def call_cmd(cmd, stdout=sys.stdout, quiet=False, Shell=False, raise_exceptions=True, use_shlex=True, timeout=None):
    """Exec command by command line like 'ln -ls "/var/log"'
    """
    if not quiet:
        print("Run %s", str(cmd))
    if use_shlex and isinstance(cmd, (str, unicode)):
        cmd = shlex.split(cmd)
    if timeout is None:
        process = subprocess.Popen(cmd, stdout=stdout, stderr=sys.stderr, Shell=shell)
        retcode = process.wait()
    else:
        process = subprocess.Popen(cmd, stdout=stdout, stderr=sys.stderr, Shell=shell)
        p = psutil.Process(process.pid)
        finish, alive = psutil.wait_procs([p], timeout)
        if len(alive) > 0:
            ps = p.children()
            ps.insert(0, p)
            print('waiting for timeout again due to child process check')
            finish, alive = psutil.wait_procs(ps, 0)
        if len(alive) > 0:
            print('process {} will be killed'.format([p.pid for p in alive]))
            for p in alive:
                p.kill()
            if raise_exceptions:
                print('External program timeout at {} {}'.format(timeout, cmd))
                raise CalledProcessTimeout(1, cmd)
        retcode = process.wait()
    if retcode and raise_exceptions:
        print("External program failed %s", str(cmd))
        raise subprocess.CalledProcessError(retcode, cmd)

Вы можете назвать это так:

cmd = 'ln -ls "/var/log"'
stdout = 'out.txt'
call_cmd(cmd, stdout)
1
Asav Patel

Модуль подпроцесса , описанный выше Eli, является очень мощным, но синтаксис, чтобы сделать системный вызов стандартным болотом и проверить его вывод, излишне распространен.

Самый простой способ сделать системный вызов - воспользоваться модулем command (только для Linux).

> import commands
> commands.getstatusoutput("grep matter alice-in-wonderland.txt")
(0, "'Then it doesn't matter which way you go,' said the Cat.")

Первый элемент в кортеже - это код возврата процесса. Второй элемент - это его стандартный вывод (и стандартная ошибка, объединенная).


Разработчики Python «устарели» как модуль команд, но это не значит, что вы не должны его использовать. Только то, что они его больше не развивают, и это нормально, потому что он уже совершенен (при своей небольшой, но важной функции).

1
Colonel Panic

Поскольку некоторые из ответов были связаны с предыдущими версиями python или использовали модуль os.system, я публикую этот ответ для таких людей, как я, которые намереваются использовать subprocess в python 3.5+. Следующее помогло мне в Linux:

import subprocess

#subprocess.run() returns a completed process object that can be inspected
c = subprocess.run(["ls", "-ltrh"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
print(c.stdout.decode('utf-8'))

Как упомянуто в документации , значения PIPE являются байтовыми последовательностями, и для правильного их отображения следует рассмотреть возможность декодирования. Для более поздних версий python text=True и encoding='utf-8' добавляются в kwargs из subprocess.run()

Вывод вышеупомянутого кода:

total 113M
-rwxr-xr-x  1 farzad farzad  307 Jan 15  2018 vpnscript
-rwxrwxr-x  1 farzad farzad  204 Jan 15  2018 ex
drwxrwxr-x  4 farzad farzad 4.0K Jan 22  2018 scripts
.... # some other lines
1
Farzad Vertigo

Если выНЕиспользуете пользовательский ввод в командах, вы можете использовать это

from os import getcwd
from subprocess import check_output
from shlex import quote

def sh(command):
    return check_output(quote(command), Shell=True, cwd=getcwd(), universal_newlines=True).strip()

И использовать его как

branch = sh('git rev-parse --abbrev-ref HEAD') 

Shell=True порождает Shell, так что вы можете использовать pipe и такие вещи Shell sh('ps aux | grep python'). Это очень удобно для запуска жестко запрограммированных команд и обработки их вывода. universal_lines=True гарантирует, что выходные данные возвращаются в виде строки вместо двоичного.

cwd=getcwd() обеспечит выполнение команды в том же рабочем каталоге, что и интерпретатор. Это удобно для работы команд git, как в приведенном выше примере с именем ветви git.

Некоторые рецепты

  • объем свободной памяти в мегабайтах: sh('free -m').split('\n')[1].split()[1]
  • свободное место на/в процентах sh('df -m /').split('\n')[1].split()[4][0:-1]
  • загрузка процессора sum(map(float, sh('ps -ef -o pcpu').split('\n')[1:])

Но это не безопасно для пользовательского ввода из документов:

Вопросы безопасности

В отличие от некоторых других функций popen, эта реализация никогда не будет явно вызывать системную оболочку. Это означает, что все символы, включая метасимволы Shell, можно безопасно передавать дочерним процессам. Если Shell вызывается явно, через Shell = True, приложение несет ответственность за обеспечение того, чтобы все пробелы и метасимволы были указаны в кавычках, чтобы избежать уязвимостей внедрения Shell.

При использовании Shell = True функция shlex.quote () может использоваться для правильного экранирования пробелов и метасимволов Shell в строках, которые будут использоваться для построения команд Shell.

Даже при использовании shlex.quote() полезно быть немного параноиком при использовании пользовательских вводов в командах Shell. Одним из вариантов является использование команды с жестким кодом для получения общего вывода и фильтрации по пользовательскому вводу. В любом случае использование Shell=False обеспечит выполнение только того процесса, который вы хотите выполнить, или вы получите ошибку No such file or directory.

Также есть некоторое влияние на производительность на Shell=True, по моим тестам он примерно на 20% медленнее, чем Shell=False (по умолчанию).

In [50]: timeit("check_output('ls -l'.split(), universal_newlines=True)", number=1000, globals=globals())
Out[50]: 2.6801227919995654

In [51]: timeit("check_output('ls -l', universal_newlines=True, Shell=True)", number=1000, globals=globals())
Out[51]: 3.243950183999914
0
geckos