Вывести в реальном времени результат команды bash, запущенной с подпроцессом в Python - PullRequest
0 голосов
/ 22 декабря 2018

Я использую модуль подпроцесса для запуска команды bash.Я хочу отобразить результат в режиме реального времени, , включая , когда новая строка не добавлена, но вывод все еще изменен.

Я использую Python 3. Мой код выполняется с подпроцессом, но я открыт для любого другого модуля.У меня есть код, который возвращает генератор для каждой новой добавленной строки.

import subprocess
import shlex

def run(command):
    process = subprocess.Popen(shlex.split(command), stdout=subprocess.PIPE)
    while True:
        line = process.stdout.readline().rstrip()
        if not line:
            break
        yield line.decode('utf-8')

cmd = 'ls -al'
for l in run(cmd):
     print(l)   

Проблема возникает, например, с командами вида rsync -P file.txt file2.txt, которые показывают индикатор выполнения.

Например, мы можем начать с создания большого файла в bash:

base64 /dev/urandom | head -c 1000000000 > file.txt 

Затем попробуйте использовать python для отображения команды rsync:

cmd = 'rsync -P file.txt file2.txt'
for l in run(cmd):
    print(l)

Сэтот код, индикатор выполнения печатается только в конце процесса, но я хочу напечатать прогресс в режиме реального времени.

1 Ответ

0 голосов
/ 22 декабря 2018

Из этого ответа вы можете отключить буферизацию при печати в python:

Вы можете пропустить буферизацию для всего процесса python, используя "python -u" (или #!/usr/bin/env python -uи т. д.) или установив переменную окружения PYTHONUNBUFFERED.

. Вы также можете заменить sys.stdout другим потоком, подобным обертке, который выполняет сброс после каждого вызова.

Примерно так (недействительно проверено) может работать ... но, возможно, есть проблемы, которые могут появиться.Например, я не думаю, что это будет работать в IDLE, поскольку sys.stdout уже заменен каким-то забавным объектом, который не любит, когда его сбрасывают.(Это можно считать ошибкой в ​​IDLE.)

>>> class Unbuffered:
..     def __init__(self, stream):
..         self.stream = stream
..     def write(self, data):
..         self.stream.write(data)
..         self.stream.flush()
..     def __getattr__(self, attr):
..         return getattr(self.stream, attr)
..
>>> import sys
>>> sys.stdout=Unbuffered(sys.stdout)
>>> print 'Hello'
Hello
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...