Python – захватывать стандартный вывод Popen И отображать его на консоли?

StackOverflow https://stackoverflow.com/questions/1283061

  •  16-09-2019
  •  | 
  •  

Вопрос

Я хочу захватить стандартный вывод из длительного процесса, запущенного через subprocess.Popen(...) поэтому я использую stdout=PIPE как аргумент.

Однако, поскольку это длительный процесс, я также хочу отправить выходные данные на консоль (как если бы я не передавал их по конвейеру), чтобы дать пользователю сценария представление о том, что он все еще работает.

Это вообще возможно?

Ваше здоровье.

Это было полезно?

Решение

Можете ли вы просто print это как ты это читаешь из трубы?

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

Буферизация, которую выполняет ваш длительный подпроцесс, вероятно, сделает вывод вашей консоли прерывистым и ухудшит UX.Я предлагаю вам вместо этого использовать ожидать (или, в Windows, мы ожидаем), чтобы обойти такую ​​буферизацию и получить плавный и регулярный вывод подпроцесса.Например (практически в любой системе unix-y после установки pexpect):

>>> import pexpect
>>> child = pexpect.spawn('/bin/bash -c "echo ba; sleep 1; echo bu"', logfile=sys.stdout); x=child.expect(pexpect.EOF); child.close()
ba
bu
>>> child.before
'ba\r\nbu\r\n'

Ба и бу появятся в нужное время (между ними около секунды).Обратите внимание, что вывод не подлежит обычной обработке терминалом, поэтому возвраты каретки остаются — вам придется самостоятельно выполнить постобработку строки (простое .replace!-) если тебе надо \n в качестве маркеров конца строки (отсутствие обработки важно только в том случае, если подпроцесс записывает двоичные данные в свой стандартный вывод - это гарантирует, что все данные останутся нетронутыми!-).

С.Комментарий Лотта указывает на Получение вывода в реальном времени с использованием подпроцесса и Перехват стандартного вывода из другого процесса в Python в реальном времени

Мне любопытно, что ответ Алекса здесь отличается от его ответа 1085071.Мои простые эксперименты с ответами на два других упомянутых вопроса дали хорошие результаты...

Я пошел и посмотрел на wexpect в соответствии с ответом Алекса выше, но должен сказать, что, прочитав комментарии к коду, у меня осталось не очень хорошее предчувствие по поводу его использования.

Я думаю, мета-вопрос здесь заключается в том, когда pexpect/wexpect станет одной из включенных в комплект батарей?

Вдохновлен предложением pty.openpty() где-то выше, протестировано на python2.6, linux.Публикую, так как потребовалось некоторое время, чтобы заставить это работать правильно, без буферизации...

def call_and_peek_output(cmd, shell=False):
    import pty, subprocess
    master, slave = pty.openpty()
    p = subprocess.Popen(cmd, shell=shell, stdin=None, stdout=slave, close_fds=True)
    os.close(slave)
    line = ""
    while True:
        try:
            ch = os.read(master, 1)
        except OSError:
            # We get this exception when the spawn process closes all references to the
            # pty descriptor which we passed him to use for stdout
            # (typically when it and its childs exit)
            break
        line += ch
        sys.stdout.write(ch)
        if ch == '\n':
            yield line
            line = ""
    if line:
        yield line

    ret = p.wait()
    if ret:
        raise subprocess.CalledProcessError(ret, cmd)

for l in call_and_peek_output("ls /", shell=True):
    pass

В качестве альтернативы вы можете передать свой процесс в тройник и захватить только один из потоков.Что-то в духе sh -c 'process interesting stuff' | tee /dev/stderr.

Конечно, это работает только в Unix-подобных системах.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top