Как получить вывод подпроцесса Python в реальном времени?

#python #python-3.x #shell #subprocess

#python #python-3.x #оболочка #подпроцесс

Вопрос:

Программа, которую я пытаюсь запустить с помощью команды оболочки, выводит одно слово в секунду. Я пытаюсь выполнить команду оболочки в скрипте Python и получить вывод в реальном времени для каждого выводимого слова. Все другие решения, которые я нашел в Интернете, на самом деле не печатают вывод в реальном времени, а скорее одну готовую строку за раз. Я хочу получить реальный вывод в реальном времени, где каждое слово печатается в реальном времени, а не в каждой строке. Это код, который я пробовал:

 cmd=['slowprogram','-m', '15', '-l', '50']
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, bufsize=1)
for line in iter(p.stdout.readline, b''):
    print(line),
p.stdout.close()
p.wait()
  

Он ждет, пока не будет завершена одна строка, и печатает ее. Есть ли способ получать обновления и печатать каждое слово в строке в режиме реального времени?

Обновить:

 p = subprocess.Popen(cmd, stdout=subprocess.PIPE, bufsize=1)
for line in iter(p.stdout.readline, b''):
    for word in iter(line):
      print(word)
p.stdout.close()
p.wait()
  

по какой-то причине возвращает кучу чисел…:

 111
117
108
100
32
104
97
118
101
32
115
97
  

Как я могу получить каждое слово из строки?

Комментарии:

1. p.stdout это ввод-вывод. Объект BytesIO; синтаксически вы можете читать из него все, что хотите, как будто это файл. Возможно, вы также захотите изучить bufsize аргумент в зависимости от ваших потребностей.

2. @YiFei Я попытался повторить каждое слово в строке, но результат был неожиданным. Я обновил свой вопрос, не могли бы вы взглянуть?

3. @YiFei я все еще не могу понять это. Не могли бы вы показать, как читать p.stdout в реальном времени?

Ответ №1:

Это один из способов сделать это, и он работал для меня в оболочке Linux. Он использует небуферизованный объект ввода-вывода и выводит по одному символу за раз. Я совершенно уверен, что есть лучшие способы, поскольку я не специалист по subprocess обработке событий or. Возможно, вы также захотите изучить asyncio .

 with subprocess.Popen(cmd, stdout=subprocess.PIPE, bufsize=0) as p:
    char = p.stdout.read(1)
    while char != b'':
        print(char.decode('UTF-8'), end='', flush=True)
        char = p.stdout.read(1)
  

Комментарии:

1. Как я могу сохранить вывод в массив без ‘b’ перед каждым словом? Когда я добавляю переменную char в массив, перед каждым словом отображается ‘b’.

2. Перефразируя: как я могу сохранить весь вывод в массив?

3. Небольшой контекст: Python имеет дело с двумя типами «строк»: строкой байтов и строкой «текста». То, что мы получаем Popen , — это строка байтов и, следовательно b , . Теперь байтовые строки могут быть преобразованы в текстовые строки путем декодирования и обратно путем кодирования.

4. Я понимаю. Когда я пытаюсь сохранить декодированные символы в массив, мои слова по какой-то причине разделяются. ’Hello’ может превратиться в ’hel’ и ’lo’. Есть ли способ сохранить весь вывод без повторного запуска всей команды?

5. Допустим, у вас есть список (или любой итерируемый, если на то пошло) L = ['hel', 'lo'] , который вы можете использовать ''.join(L) . Но в зависимости от ваших потребностей вы также можете сохранить и добавить к строке с самого начала.