Вызов внешней команды в Python - PullRequest
4261 голосов
/ 18 сентября 2008

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

Ответы [ 56 ]

58 голосов
/ 29 апреля 2011

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

56 голосов
/ 11 апреля 2013

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

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

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

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

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

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

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.

49 голосов
/ 28 октября 2012

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

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 голосов
/ 15 ноября 2012

Обновление:

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

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

Я рекомендую попробовать 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'>]
37 голосов
/ 18 апреля 2013

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

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

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

import commands
commands.getoutput("your command here")
or
commands.getstatusoutput("your command here")
32 голосов
/ 18 сентября 2008

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

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

import os
os.system('cat testfile')
30 голосов
/ 10 октября 2014

Есть также Пламб

>>> 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
29 голосов
/ 18 сентября 2008

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

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

28 голосов
/ 18 октября 2017

Вызов внешней команды в 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 будет повторно вызвано после того, как дочерний процесс прекращено.

Если проверка верна, и процесс завершается с ненулевым кодом выхода, a Возникнет исключение 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, указанная в source . Я думаю, что это наиболее точная инкапсуляция информации (в отличие от 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 будет оставлено читателю в качестве упражнения.

25 голосов
/ 29 июня 2015

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

import os

cmd = 'ls -al'

os.system(cmd)

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

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

...