2014-09-18 4 views
2

Я пытаюсь прочитать последнюю строку из команды типа «apt-get download firefox». Обычно выход будет какПоследняя небуферизованная строка не может быть прочитана

Get:1 http://archive.ubuntu.com/ubuntu/ utopic/main firefox amd64 32.0+build1-0ubuntu2 [34.9 MB] 
2% [1 firefox 646 kB/34.9 MB 2%] 

с последней строкой постоянно обновлять (не писать новую строку, пока она не достигнет 100%). Моя цель - теперь прочитать прогресс в реальном времени. Вот мой текущий код примера:

#!/usr/bin/python3 -u 
# coding=utf-8 

import subprocess, sys 

pipe = subprocess.Popen(['apt-get', 'download', 'firefox'], 0, stderr = subprocess.PIPE, stdout = subprocess.PIPE) 
while True: 
    content = pipe.stdout.read(1).decode() 
    if content == '': 
     break 
    sys.stdout.write(content) 
    sys.stdout.flush() 
pipe.wait() 

Я отключил буферизацию вывода для вызова подпроцесса, а также для дискретного выхода для процесса Python (с -u аргументом). Но я получаю только первую строку, но не прогресс второй линии. Кто-нибудь знает, как я могу это достичь?

+0

вам нужны либо потоки, либо async.io, чтобы читать * оба * потоки одновременно. См. [Отображение вывода подпроцесса в stdout и перенаправление его] (http://stackoverflow.com/q/25750468/4279). – jfs

+0

Вам нужно захватить 'Get: 1 http: // ..' line (stdout?), Или это достаточно, если вы получите только последнюю строку прогресса (stderr?)? – jfs

+0

Что нужно проверить: 1. «apt-get' пишет только в stdout/stderr или может [писать на терминал напрямую] (http://stackoverflow.com/q/20980965/4279)? 2. Использует ли [block-buffering, если stdout является каналом] (http://stackoverflow.com/q/20503671/4279)? 3. Показывает ли строка прогресса, если stderr перенаправляется на трубу? – jfs

ответ

0

Если стандартный вывод из apt-get перенаправляется на трубе, например,

$ apt-get download firefox | cat 

тогда не сообщать о прогрессе (последняя строка, например, 2% [1 firefox 646 kB/34.9 MB 2%] будет не быть на выходе). stdout=subprocess.PIPE естественно создает трубу; поэтому apt-get не печатает ход загрузки в вашем случае.

Если вы хотите, и захватить apt-get выход и увидеть его на экране в режиме реального времени с последней строкой (отчет о ходе работ) присутствует, то вы могли бы use pexpect module to trick the child process into thinking that it runs in a terminal:

import sys 
import pexpect # $ pip install pexpect 

output, exitstatus = pexpect.runu('apt-get download firefox', 
            logfile=sys.stdout, 
            withexitstatus=1) 

Вы могли бы сделать то же самое с помощью только STDLIB pty модуль:

#!/usr/bin/env python3 
import os 
import pty 

output = [] 
def read(fd): 
    data = os.read(fd, 1024) 
    output.append(data) 
    return data 
status = pty.spawn(['apt-get', 'download', 'firefox'], read) 

@eryksun on Python Issue tracker suggestedapt-get «s --quiet вариант:

#!/usr/bin/env python3 
import shlex 
from io import TextIOWrapper 
from subprocess import Popen, PIPE 

output = [] 
with Popen(shlex.split("apt-get --quiet=0 download firefox"), 
      stdout=PIPE, bufsize=1) as p: 
    # recognize '\r' as newline but don't convert it to '\n' 
    for line in TextIOWrapper(p.stdout, newline=''): 
     print(line, end='', flush=True) # print to terminal 
     output.append(line) # save for later 
print(p.returncode) 
Смежные вопросы