Получение вывода subprocess.call()

Как я могу получить выходные данные процесса, запущенного с использованием subprocess.call()?

Передача объекта StringIO.StringIO в stdout дает StringIO.StringIO ошибку:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/subprocess.py", line 444, in call
    return Popen(*popenargs, **kwargs).wait()
  File "/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/subprocess.py", line 588, in __init__
    errread, errwrite) = self._get_handles(stdin, stdout, stderr)
  File "/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/subprocess.py", line 945, in _get_handles
    c2pwrite = stdout.fileno()
AttributeError: StringIO instance has no attribute 'fileno'
>>> 

Ответ 1

Выход из subprocess.call() должен быть перенаправлен только в файлы.

Вместо этого следует использовать subprocess.Popen(). Затем вы можете передать subprocess.PIPE для параметров stderr, stdout и/или stdin и прочитать из труб с помощью метода communicate():

from subprocess import Popen, PIPE

p = Popen(['program', 'arg1'], stdin=PIPE, stdout=PIPE, stderr=PIPE)
output, err = p.communicate(b"input data that is passed to subprocess' stdin")
rc = p.returncode

Мысль о том, что файл-подобный объект, используемый subprocess.call(), должен иметь реальный файловый дескриптор и таким образом реализовать метод fileno(). Просто использование любого файла-подобного объекта не поможет.

Подробнее см. здесь.

Ответ 2

Если у вас версия Python> = 2.7, вы можете использовать subprocess.check_output, который в основном делает именно то, что вам нужно (он возвращает стандартный вывод в виде строки).

Простой пример (версия для Linux, см. Примечание):

import subprocess

print subprocess.check_output(["ping", "-c", "1", "8.8.8.8"])

Обратите внимание, что команда ping использует нотацию linux (-c для count). Если вы попробуете это в Windows, не забудьте изменить его на -n для того же результата.

Как прокомментировано ниже, вы можете найти более подробное объяснение в этом другом ответе.

Ответ 3

У меня есть следующее решение. Он фиксирует код выхода, stdout и stderr также исполняемой внешней команды:

import shlex
from subprocess import Popen, PIPE

def get_exitcode_stdout_stderr(cmd):
    """
    Execute the external command and get its exitcode, stdout and stderr.
    """
    args = shlex.split(cmd)

    proc = Popen(args, stdout=PIPE, stderr=PIPE)
    out, err = proc.communicate()
    exitcode = proc.returncode
    #
    return exitcode, out, err

cmd = "..."  # arbitrary external command, e.g. "python mytest.py"
exitcode, out, err = get_exitcode_stdout_stderr(cmd)

У меня также есть сообщение в блоге здесь.

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

Ответ 4

Для 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

Недавно я только что понял, как это сделать, и вот какой-то пример кода из моего текущего проекта:

#Getting the random picture.
#First find all pictures:
import shlex, subprocess
cmd = 'find ../Pictures/ -regex ".*\(JPG\|NEF\|jpg\)" '
#cmd = raw_input("shell:")
args = shlex.split(cmd)
output,error = subprocess.Popen(args,stdout = subprocess.PIPE, stderr= subprocess.PIPE).communicate()
#Another way to get output
#output = subprocess.Popen(args,stdout = subprocess.PIPE).stdout
ber = raw_input("search complete, display results?")
print output
#... and on to the selection process ...

Теперь вы получаете вывод команды, хранящейся в переменной "output". "stdout = subprocess.PIPE" сообщает классу создать файловый объект с именем "stdout" из Popen. Метод communication(), из того, что я могу сказать, просто действует как удобный способ возврата кортежа вывода и ошибок из процесса, который вы запускали. Кроме того, процесс запускается при создании экземпляра Popen.

Ответ 6

В Ipython оболочке:

In [8]: import subprocess
In [9]: s=subprocess.check_output(["echo", "Hello World!"])
In [10]: s
Out[10]: 'Hello World!\n'

На основе ответа sargue. Кредит для sargue.

Ответ 7

Следующее захватывает stdout и stderr процесса в одной переменной. Это Python 2 и 3 совместимы:

from subprocess import check_output, CalledProcessError, STDOUT

command = ["ls", "-l"]
try:
    output = check_output(command, stderr=STDOUT).decode()
    success = True 
except CalledProcessError as e:
    output = e.output.decode()
    success = False

Если ваша команда является строкой, а не массивом, добавьте к ней префикс:

import shlex
command = shlex.split(command)