Распечатать в реальном времени результат команды bash, запущенной с подпроцессом в Python

Я использую модуль подпроцесса для запуска команды 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)

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

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
0
194
1

Ответы 1

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

You can skip buffering for a whole python process using "python -u" (or #!/usr/bin/env python -u etc) or by setting the environment variable PYTHONUNBUFFERED.

You could also replace sys.stdout with some other stream like wrapper which does a flush after every call.

Something like this (not really tested) might work...but there are probably problems that could pop up. For instance, I don't think it will work in IDLE, since sys.stdout is already replaced with some funny object there which doesn't like to be flushed. (This could be considered a bug in IDLE though.)

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

Спасибо за помощь. Но, хотя -u, безусловно, полезен, я хочу отображать результат сценария bash через python. Например, я хочу иметь возможность использовать команду run внутри записной книжки jupyter и печатать результат, или ждать, пока будет записана определенная строка для выполнения действия, или просто распечатать результат команды bash. Если я просто использую -u и (например), os.system (cmd), я не смогу этого сделать.

bombadilhom 22.12.2018 17:23

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