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

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

4296
18 сент. '08 в 4:35
источник поделиться
57 ответов
  • 1
  • 2

В 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
14
17 июня '16 в 12:14
источник

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

>>> 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
12
15 сент. '18 в 1:20
источник

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

from commands import getstatusoutput

try:
    return getstatusoutput("ls -ltr")
except Exception, e:
    return None
12
25 июля '12 в 9:51
источник

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

11
02 дек. '17 в 21:47

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

Это возвращаемые значения из метода 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]
11
14 окт. '15 в 10:12
источник

Чтобы получить идентификатор сети из нейтрона 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
11
20 июля '16 в 12:50
источник

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

Он получается, если процесс выполняется с использованием метода 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])
8
23 марта '18 в 5:30
источник

Существует два основных способа выполнения команд оболочки с использованием 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
7
05 февр. '19 в 3:13
источник

Вызов внешней команды в 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. Мы можем запустить команду в фоновом режиме и дождаться ее завершения. И после этого мы можем получить stdout и stderr.

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]
7
04 апр. '18 в 9:57
источник

Как пример (в 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.

7
31 янв. '18 в 20:42
источник

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

Python Subprocess check_output подходит для

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

import subprocess
proc = subprocess.check_output('ipconfig /all')
print proc
7
11 окт. '16 в 5:26
источник

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

Например:

In [9]: mylist = !ls

In [10]: mylist
Out[10]:
['file1',
 'file2',
 'file3',]
7
20 июня '13 в 2:18
источник

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

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
24 июня '16 в 14:29
источник

Существует множество различных способов запуска внешних команд в Python, и все они имеют свои собственные плюсы и недостатки.

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

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

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

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

6
17 апр. '13 в 17:10
источник

Для Python 3.5+ рекомендуется использовать функцию запуска из модуля подпроцесса. Это возвращает объект 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
17 марта '16 в 13:48
источник

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

Например,

!ls -ilF
5
08 мая '18 в 23:49
источник

Простым способом является использование модуля os:

import os
os.system('ls')

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

import subprocess
subprocess.check_call('ls')

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

import subprocess
r = subprocess.check_output('ls')
4
25 авг. '14 в 0:46
источник

Существует много способов вызова команды.

  • Например:

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

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

  • os.system(cmd,...)

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

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

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

import os
cmd = " ".join(exename,parameters)
os.popen(cmd)
4
12 сент. '16 в 12:44
источник

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

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

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

pip install citizenshell

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

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

Вы можете отделить стандартный вывод от стандартного и извлечь код завершения следующим образом:

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.

4
30 окт. '18 в 14:40
источник

Использование функции Popen модуля subprocess Python - это самый простой способ запуска команд 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
24 июля '15 в 22:12
источник

Используйте 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
12 апр. '14 в 14:58
источник

Так как некоторые ответы были связаны с предыдущими версиями python или использовали модуль os.system я 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
2
29 янв. '19 в 8:11
источник

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

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)
2
25 окт. '17 в 2:30
источник

После некоторых исследований у меня есть следующий код, который очень хорошо работает для меня. Он в основном печатает как 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
14 марта '14 в 5:59
источник

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

  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
28 апр. '16 в 14:18
источник

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

Самый простой способ сделать системный вызов - это модуль команд (только для 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
18 апр. '13 в 20:39
источник

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

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 будет порождать оболочку, поэтому вы можете использовать pipe и такие вещи оболочки 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:]) загрузки процессора sum(map(float, sh('ps -ef -o pcpu').split('\n')[1:])

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

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

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

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

Даже при использовании shlex.quote() полезно быть немного параноиком при использовании пользовательских вводов для команд оболочки. Одним из вариантов является использование команды с жестким кодом для получения общего вывода и фильтрации по вводу пользователя. В любом случае, использование 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
31 марта '19 в 15:21
источник
  • 1
  • 2

Посмотрите другие вопросы по меткам или Задайте вопрос