ловля stdout в в реальном времени от подпроцесса

Заключение в кавычки от MSDN

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

74
задан Mad Physicist 16 May 2017 в 14:43
поделиться

2 ответа

Change the stdout from the rsync process to be unbuffered.

p = subprocess.Popen(cmd,
                     shell=True,
                     bufsize=0,  # 0=unbuffered, 1=line-buffered, else buffer-size
                     stdin=subprocess.PIPE,
                     stderr=subprocess.PIPE,
                     stdout=subprocess.PIPE)
4
ответ дан 24 November 2019 в 11:53
поделиться

Некоторые практические правила для подпроцесса .

  • Никогда не используйте shell = True . Он без нужды вызывает дополнительный процесс оболочки для вызова вашей программы.
  • При вызове процессов аргументы передаются в виде списков. sys.argv в python является списком, как и argv в C. Таким образом, вы передаете список в Popen для вызова подпроцессов. , а не строку.
  • Не перенаправляйте stderr на PIPE , когда вы его не читаете.
  • Не перенаправляйте stdin , когда вы не пишете на него.

Пример:

import subprocess, time, os, sys
cmd = ["rsync.exe", "-vaz", "-P", "source/" ,"dest/"]

p = subprocess.Popen(cmd,
                     stdout=subprocess.PIPE,
                     stderr=subprocess.STDOUT)

for line in iter(p.stdout.readline, b''):
    print(">>> " + line.rstrip())

Тем не менее, вероятно, что rsync буферизует свой вывод, когда обнаруживает, что он подключен к труба вместо терминала. Это поведение по умолчанию - при подключении к трубе программы должны явно сбрасывать стандартный вывод для результатов в реальном времени, иначе стандартная библиотека C будет буферизована.

Чтобы проверить это, попробуйте вместо этого запустить это:

cmd = [sys.executable, 'test_out.py']

и создать файл test_out.py с содержимым:

import sys
import time
print ("Hello")
sys.stdout.flush()
time.sleep(10)
print ("World")

Выполнение этого подпроцесса должно дать вам «Hello» и подождать 10 секунд, прежде чем дать «World». Если это происходит с кодом Python выше, а не с rsync , это означает, что сам rsync буферизует вывод, поэтому вам не повезло.

Решением будет прямое подключение в pty , используя что-то вроде pexpect .

import sys
import time
print ("Hello")
sys.stdout.flush()
time.sleep(10)
print ("World")

Выполнение этого подпроцесса должно дать вам «Hello» и подождать 10 секунд, прежде чем дать «World». Если это происходит с кодом Python выше, а не с rsync , это означает, что сам rsync буферизует вывод, поэтому вам не повезло.

Решением будет прямое подключение в pty , используя что-то вроде pexpect .

import sys
import time
print ("Hello")
sys.stdout.flush()
time.sleep(10)
print ("World")

Выполнение этого подпроцесса должно дать вам «Hello» и подождать 10 секунд, прежде чем дать «World». Если это происходит с кодом Python выше, а не с rsync , это означает, что сам rsync буферизует вывод, поэтому вам не повезло.

Решением будет прямое подключение в pty , используя что-то вроде pexpect .

92
ответ дан 24 November 2019 в 11:53
поделиться
Другие вопросы по тегам:

Похожие вопросы: