2009-09-07 2 views
34

Я хочу, чтобы результат выполнялся Test_Pipe.py, я пробовал следующий код в Linux, но он не работал.Как получить выход из подпроцесса.Popen()

Test_Pipe.py

import time 
while True : 
    print "Someting ..." 
    time.sleep(.1) 

Caller.py

import subprocess as subp 
import time 

proc = subp.Popen(["python", "Test_Pipe.py"], stdout=subp.PIPE, stdin=subp.PIPE) 

while True : 
    data = proc.stdout.readline() #block/wait 
    print data 
    time.sleep(.1) 

Линия proc.stdout.readline() была заблокирована, так что никаких отпечатков данных из.

+0

Duplicate: http://stackoverflow.com/search?q=%5Bpython%5D+subprocess+output, http://stackoverflow.com/questions/803265/getting-realtime-output-using-subprocess, http: //stackoverflow.com/questions/1277866/python-subprocess-module-looping-over-stdout-of-child-process –

ответ

39

Вы, очевидно, можете использовать subprocess.communicate, но я думаю, что вы ищете вход и выход в реальном времени.

readline был заблокирован, так как процесс, вероятно, ожидает вашего ввода. Вы можете читать посимвольно, чтобы преодолеть это, как следующее:

import subprocess 
import sys 

process = subprocess.Popen(
    cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE 
) 

while True: 
    out = process.stdout.read(1) 
    if out == '' and process.poll() != None: 
     break 
    if out != '': 
     sys.stdout.write(out) 
     sys.stdout.flush() 
+2

[вам не нужно 'process.poll()' в этом случае] (http: // stackoverflow.com/a/17701672/4279). – jfs

12

Чтобы избежать многих проблем, которые всегда могут возникнуть при буферизации для таких задач, как «получение вывода подпроцесса к основному процессу в реальном масштабе времени», я всегда рекомендуется использовать pexpect для всех платформ, отличных от Windows, wexpect на Windows, а не subprocess, когда такие задачи желательны.

+0

Обновлено ссылка на pexpect: https://github.com/pexpect/pexpect –

20

Фрагмент Надии действительно работает, но вызов чтения с помощью 1 байтового буфера очень не рекомендуется. Лучший способ сделать это было бы установить дескриптор STDOUT файла блокирующими используя Fcntl

fcntl.fcntl(
    proc.stdout.fileno(), 
    fcntl.F_SETFL, 
    fcntl.fcntl(proc.stdout.fileno(), fcntl.F_GETFL) | os.O_NONBLOCK, 
) 

, а затем с помощью выберите, чтобы проверить, если данные готовы

while proc.poll() == None: 
    readx = select.select([proc.stdout.fileno()], [], [])[0] 
    if readx: 
     chunk = proc.stdout.read() 
     print chunk 

Она верна в том, что ваша проблема должен отличаться от того, что вы разместили в качестве Caller.py и Test_Pipe.py, как работайте.

+0

Он не будет выводить результат раньше, чем код в вопросе из-за проблемы с блочной буферизацией.См. Мой ответ] (http://stackoverflow.com/a/17701672/4279). – jfs

+0

Код действительно выводит результат в реальном времени. У вас была проблема с этим? –

+0

перейдите по ссылке в комментарии. – jfs

7

Test_Pipe.py буферы его стандартный вывод по умолчанию, так proc в Caller.py не вижу выхода, пока буфер ребенка не заполнится (если размер буфера 8KB затем она занимает около одной минуты, чтобы заполнить Test_Pipe.py).

Чтобы сделать вывод небуферизованным (с буферизацией строки для текстовых потоков), вы можете передать -u flag дочернему скрипту Python. Это позволяет читать подпроцесс выходные построчно в „реальное время“:

import sys 
from subprocess import Popen, PIPE 

proc = Popen([sys.executable, "-u", "Test_Pipe.py"], stdout=PIPE, bufsize=1) 
for line in iter(proc.stdout.readline, b''): 
    print line, 
proc.communicate() 

См ссылка в Python: read streaming input from subprocess.communicate() о том, как решить проблему блока буферизации для дочерних процессов непитоновских.

+1

Снова вы используете 1 байтовый буфер, который невероятно неэффективен. –

+4

@DerrickPetzold: неправильно. 'bufsize = 1' означает« строка-буферизация ». Он использует тот же размер буфера, что и 'bufsize = -1'. Вы могли бы узнать, что оба ваших комментария ошибочны, если вы на самом деле должны запускать код (сравнить производительность времени и измерить время до того, как будет прочитан первый байт) – jfs

+1

Мне нравится этот способ сделать это, потому что вы можете печатать непосредственно на экране а также сохранить результаты popen, чтобы что-то сделать, а затем проверить код ошибки и т. д. ... thumbs up =) Я запускаю его без bufsize и отлично работает для меня в своем коде. – pelos

Смежные вопросы