Получение вывода 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'
>>> 

person Jeffrey Aylesworth    schedule 03.01.2010    source источник
comment
Ответ Майка правильный. Обратите внимание, что StringIO работает как файл в большинстве случаев, но не во всех. В вашем случае это не работает, потому что модуль multiprocessing в некоторых случаях принимает реальные файлы. Это могло быть исправлено: см. bugs.python.org/issue5313, чтобы узнать о соответствующей ошибке.   -  person Michael Greene    schedule 04.01.2010
comment
На самом деле communicate() использует select.select(), который принимает только файловые дескрипторы, так что на самом деле это не ошибка. Я был весьма сбит с толку, когда впервые столкнулся с этим, и изучение глубин subprocess.py многому меня научило !.   -  person Mike    schedule 04.01.2010
comment
Я думаю, что subprocess.run делает это проще, чем в Python 3.5. Я добавлю ответ, когда у меня будет возможность.   -  person Mark Amery    schedule 11.04.2016
comment
Обратите внимание, что принятый ответ устарел. Простой ответ для Python 2.7 будет subprocess.check_output(); в Python 3.5+ вы также захотите посмотреть subprocess.run(). Не должно быть необходимости или желания использовать raw subprocess.Popen(), если вы можете этого избежать, хотя некоторые более сложные варианты использования требуют этого (и тогда вам придется самостоятельно выполнить необходимую сантехнику). На странице информации о тегах Stack Overflow subprocess есть полезные ресурсы для менее тривиальных случаев.   -  person tripleee    schedule 05.02.2021


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

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

person Mike    schedule 03.01.2010
comment
эта страница docs.python.org/library/subprocess.html#module-subprocess не рекомендует использовать subprocess.PIPE, есть идеи, как это преодолеть? - person Vladimir Keleshev; 14.12.2011
comment
Кроме того, вопрос определяет использование subprocess.call, а ответ Майка фактически использует Popen, поскольку subprocess.call возвращает только код возврата, но не имеет средств доступа к любому из потоков. Это при использовании 2.6, при использовании 2.7 можно использовать ответ @Sergi - person Willyfrog; 12.11.2012
comment
Это кажется неправильным предложением ... - person lpapp; 15.11.2013
comment
@Halst: документы предупреждают о PIPE для вызова call() (не используйте PIPE в этом случае). Можно использовать PIPE с subprocess.Popen, например, output, _ = Popen(..., stdout=PIPE).communicate(), как предполагает этот ответ. - person jfs; 11.01.2014
comment
//, я могу подтвердить, что это работает. @ J.F.Sebastian, какая разница между subprocess.call () и subprocess.Popen () делает PIPE менее безопасным для первого? - person Nathan Basanese; 03.09.2015
comment
@NathanBasanese: вкратце: не использует PIPE, если вы не потребляете канал. call() равно Popen().wait(), и поэтому он не использует каналы (как только соответствующий буфер канала ОС заполняется, дочерний процесс зависает навсегда). Popen().communicate() записывает / читает данные из каналов, если используется PIPE, что позволяет дочернему процессу продолжить работу. - person jfs; 03.09.2015
comment
// , Ах хорошо. В этом есть смысл. Странно, что это даже позволяет использовать PIPE в качестве аргумента. В любом случае, я был хорошим гражданином StackOverFlow и задал ему вопрос: stackoverflow.com/questions/32364849/, не могли бы вы добавить это в качестве ответа? - person Nathan Basanese; 03.09.2015
comment
Что означает буква b в p.communicate(b"in? - person clankill3r; 08.03.2017
comment
@ clankill3r он делает литерал Bytes вместо строкового литерала в Python 3. stackoverflow.com/questions/6269765/ - person Clay; 16.06.2017
comment
Нет, он не работает с Python 2.7.15. Пусто output. - person Arkady; 07.08.2018

Если у вас версия 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 для того же результата.

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

person sargue    schedule 02.01.2012
comment
Нашел еще один ответ с рабочим кодом. Пожалуйста, проголосуйте, если вы его использовали. - person Droogans; 19.07.2012
comment
Но имейте в виду, что check_output вызовет исключение, если процесс вернет ненулевой код выхода. - person tobltobs; 04.08.2015
comment
Обратите внимание, что check_output страдает от проблемы с заполнением PIPE как run, поскольку он просто вызывает run. Так что, если у вас есть процесс, генерирующий немного больше вывода, он будет зависать на неопределенное время. Решение Popen от @ Mike's и Ответы @Jabba работают намного лучше - person ChrisWue; 26.05.2017
comment
Но другой ответ не демонстрирует, как читать stdout из check_call. - person Ray Salemi; 28.09.2017
comment
Вы действительно должны указать это в своем ответе. - person Big McLargeHuge; 07.03.2018
comment
Что хранится на выходе? Если запущен, например, сценарий оболочки, то это значение в команде echo / cat или что-то еще? - person arqam; 25.09.2018
comment
это то, что обычно печатается в двоичном формате. вы можете сделать subprocess.check_output(['ls", "/"]).decode() например - person ozgeneral; 20.02.2019
comment
check_output также имеет барьер для проверки. В моем текущем варианте использования мне действительно нужно игнорировать ненулевые возвращаемые значения. - person macetw; 16.06.2020

Для 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)
person Chiel ten Brinke    schedule 19.01.2016
comment
Это блестящий ответ. Но не упускайте из виду часть 'stdout = PIPE', как я сделал в первый раз, иначе результат будет очень недолговечным! - person excyberlabber; 28.07.2017
comment
Вместо universal_newlines=True вы должны использовать text=True, поскольку первое сохранено для обратной совместимости. - person tobiasraabe; 08.05.2019
comment
Рекомендуется использовать функцию run - у меня это не работает, когда я использую эти параметры, похоже, проблема с Windows. Решил, добавив shell=True в команду run! И независимо от того, какую ОС вы используете, если у вас Python 3.7+, замените stdout=PIPE, stderr=PIPE на capture_output=True, чтобы добавить буфер, который не будет заблокирован. - person Post169; 03.10.2019
comment
@ Post169 Отличный ответ для поклонников Python 3.7+! Итак, я запустил rc = subprocess.run(ogrList, capture_output=True), затем print("\n", rc.stdout), и он отлично сработал! Спасибо! - person user7587050; 19.09.2020

У меня есть следующее решение. Он фиксирует код выхода, 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. файлы.

person Jabba    schedule 08.01.2014
comment
@Jabba по какой-то причине это не сработает, если я не добавлю shell=True к аргументам Popen (), не могли бы вы объяснить, почему? - person JaeGeeTee; 18.02.2014
comment
@JaeGeeTee: Какую команду вы хотели вызвать? Я предполагаю, что вы хотели вызвать команду, содержащую каналы (например, cat file.txt | wc -l). - person Jabba; 20.02.2014
comment
@Jabba Я бегал ping 127.0.0.1 - person JaeGeeTee; 21.02.2014
comment
@JaeGeeTee - попробовать явно использовать / bin / ping? - person cdyson37; 24.04.2014
comment
На самом деле не отвечает на вопрос, как использовать call или check_call для очень небольшого вывода. - person Ray Salemi; 28.09.2017
comment
Разве мы не должны сначала выполнить proc.wait () перед чтением и ошибаемся? - person infoclogged; 06.10.2017

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

#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 ...

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

person Cheesemold    schedule 14.07.2010
comment
На самом деле не отвечает на вопрос, как использовать вызов (разумно). - person Ray Salemi; 28.09.2017

Ключ в том, чтобы использовать функцию subprocess.check_coutput

Например, следующая функция захватывает stdout и stderr процесса и возвращает их, а также информацию о том, был ли вызов успешным. Он совместим с Python 2 и 3:

from subprocess import check_output, CalledProcessError, STDOUT

def system_call(command):
    """ 
    params:
        command: list of strings, ex. `["ls", "-l"]`
    returns: output, success
    """
    try:
        output = check_output(command, stderr=STDOUT).decode()
        success = True 
    except CalledProcessError as e:
        output = e.output.decode()
        success = False
    return output, success

output, success = system_call(["ls", "-l"])

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

from subprocess import check_output, CalledProcessError, STDOUT
import shlex

def system_call(command):
    """ 
    params:
        command: string, ex. `"ls -l"`
    returns: output, success
    """
    command = shlex.split(command)
    try:
        output = check_output(command, stderr=STDOUT).decode()
        success = True 
    except CalledProcessError as e:
        output = e.output.decode()
        success = False
    return output, success

output, success = system_call("ls -l")
person Zags    schedule 06.11.2017
comment
Нп, искать было несложно. Кстати, у него также есть опция input=, позволяющая указать ввод для передачи в команду вместо этого сверхсложного способа сделать это с помощью Popen. - person sudo; 18.11.2017
comment
отлично, потому что он работает даже с ненулевым кодом выхода! - person Jason; 16.07.2018
comment
Абсолютно отличный способ сделать это, именно то, что я искал. И чтобы уточнить комментарий Джейсона: с ненулевым кодом выхода вы попадете в часть обработчика исключений, поэтому ваш success будет False - person retif; 31.08.2020

В Ipython оболочке:

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

На основании ответа Сарга. Благодарность саргу.

person jhegedus    schedule 05.09.2015
comment
s=subprocess.check_output(["echo", "Hello World!"]); print(s) печатается как b'Hello World!\n' как мне избавиться от b''index? @jhegedus - person alper; 31.08.2018
comment
попробуйте b'Hello World! \ n'.decode (utf-8) - person Soumyajit; 18.08.2019