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

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

Проходя StringIO.StringIO Возражать stdout выдает эту ошибку:

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

7 ответов

Решение

Выход из 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() метод. Просто использование любого подобного файлу объекта не сработает.

Смотрите здесь для получения дополнительной информации.

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

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

import subprocess

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

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

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

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

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

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. файлы.

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

#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. Насколько я могу судить, метод connect () действует просто как удобный способ возврата кортежа выходных данных и ошибок из процесса, который вы запустили. Кроме того, процесс запускается при создании экземпляра Popen.

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

from subprocess import check_output

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)

В Ipython ракушка:

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

На основании ответа Сарга. Отдайте саргу.

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