Вывод в реальном времени из скрипта Python с использованием subprocess.Popen () - PullRequest
0 голосов
/ 17 мая 2018

После поиска я определил функцию для выполнения команды, как в терминале:

import shlex
import subprocess
def execute_cmd(cmd):
    p = subprocess.Popen(shlex.split(cmd), stdout=subprocess.PIPE, stderr=subprocess.PIPE)

    for line in iter(p.stdout.readline, b''):  # b'' here for python3
        sys.stdout.write(line.decode(sys.stdout.encoding))

    error = p.stderr.read().decode()
    if error:
        raise Exception(error)

Он работает нормально (вывод в реальном времени), когда я

execute_cmd('ping -c 5 www.google.com')

Однако, когдая использую execute_cmd для запуска скрипта Python, вывод будет распечатан до завершения процесса.

execute_cmd('python test.py')

script: test.py

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import time

print('hello')
time.sleep(2)
print('hello, again')

Как я могу это исправить?спасибо!


Извините, что не объяснил, почему «перехватите стандартный вывод и снова запишите его в стандартный вывод».Здесь я действительно хочу поймать вывод сценариев в логгер, логгер выводит их на экран (StreamHandler) и файл журнала (FileHandler).Я собрал и протестировал часть логгера, теперь часть «выполнить».И игнорировать параметр stdout=, кажется, не работает.

конвейер:

  1. регистратор настроек;
  2. перенаправить STDOUT, STDERR на регистратор;
  3. выполнить сценарии;

Из-за шага 2, если я игнорирую параметр stdout=, выходные данные сценариев будут по-прежнему выводиться в STDOUT и не будут регистрироваться в файле.

Может быть, яможно установить stdout= в логгер?

1 Ответ

0 голосов
/ 17 мая 2018

Это общая проблема базовой системы вывода, особенно в Linux или других Unix-подобных системах. Библиотека io достаточно умна, чтобы сбрасывать вывод на каждом \n, когда обнаруживает, что вывод направлен на терминал. Но эта автоматическая очистка не происходит, когда вывод перенаправляется в файл или канал, вероятно, из-за производительности. Это не проблема, когда важны только данные, но это приводит к странному поведению, когда время тоже имеет значение.

К сожалению, я не знаю простого способа исправить это из программы вызывающей стороны (*). Единственная возможность состоит в том, чтобы вызывать силу вызываемого абонента в каждой строке / блоке или использовать небуферизованный вывод:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import time
import sys

print('hello')
sys.stdout.flush()
time.sleep(2)
print('hello, again')

(*) Пуленепробиваемый способ - использовать псевдотерминал. Абонент контролирует главную сторону и передает клиентскую сторону клиенту. Библиотека обнаружит терминал и автоматически сбросит значение в каждой строке. Но он больше не переносим за пределы мира Unix и на самом деле не является простым способом.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...