как я могу добиться вывода динамически с помощью модуля подпроцесса (пока внешняя программа продолжает работать) в python. Внешняя программа, из которой я хочу получать динамический вывод, - нгрок, ngrok продолжает работать, пока работает моя программа, но мне нужен вывод во время выполнения процесса, чтобы я мог извлечь вновь сгенерированный «URL-адрес пересылки»
когда я пытаюсь сделать:
cmd = ['ngrok', 'http', '5000']
output = subprocess.Popen(cmd, stdout=subprocess.PIPE, buffersize=1)
он продолжает хранить вывод в буферах






Я знаю, что это дубликат, но сейчас я не могу найти подходящих тем по этому поводу. Все, что я получаю, это output.communicate().
Вот фрагмент, который может быть полезен:
import subprocess
cmd = ['ngrok', 'http', '5000']
process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
while process.poll() is None:
print(process.stdout.readline())
print(process.stdout.read())
process.stdout.close()
Это выведет все, что выводит процесс, через ваш скрипт на ваш вывод. Это делается путем поиска символа новой строки перед выводом.
Этот фрагмент кода работал бы, если бы не тот факт, что ngrok использует ncurses и / или передает вывод своему собственному пользователю / потоку, как когда SSH запрашивает пароль, когда вы выполняете ssh user@host.
process.poll() проверяет, есть ли у процесса код выхода (если он мертв), если нет, он продолжает цикл и печатает что-либо из stdout процесса.
Есть и другие (лучшие) способы сделать это, но это тот минимум, который я могу вам дать, чтобы он не усложнялся очень быстро.
Например, process.stdout.read() можно было бы использовать вместе с select.select() для достижения лучшего буферизованного вывода там, где новые строки пугают. Потому что, если \n так и не появится, в приведенном выше примере может зависнуть все ваше приложение.
Здесь много буферов-ловушек, о которых вам нужно знать, прежде чем делать подобные вещи вручную. В противном случае используйте process.communicate().
Обновлено: чтобы обойти ограничение / ограничение ввода-вывода, используемое ngrok, вы можете использовать pty.fork() и читать дочерний стандартный вывод через модуль os.read:
#!/usr/bin/python
## Requires: Linux
## Does not require: Pexpect
import pty, os
from os import fork, waitpid, execv, read, write, kill
def pid_exists(pid):
"""Check whether pid exists in the current process table."""
if pid < 0:
return False
try:
kill(pid, 0)
except (OSError, e):
return e.errno == errno.EPERMRM
else:
return True
class exec():
def __init__(self):
self.run()
def run(self):
command = [
'/usr/bin/ngrok',
'http',
'5000'
]
# PID = 0 for child, and the PID of the child for the parent
pid, child_fd = pty.fork()
if not pid: # Child process
# Replace child process with our SSH process
execv(command[0], command)
while True:
output = read(child_fd, 1024)
print(output.decode('UTF-8'))
lower = output.lower()
# example input (if needed)
if b'password:' in lower:
write(child_fd, b'some response\n')
waitpid(pid, 0)
exec()
Здесь все еще есть проблема, и я не совсем понимаю, что это и почему. Я предполагаю, что процесс как-то ждет сигнала / флеша. Проблема в том, что он печатает только первые «установочные данные» ncurses, то есть стирает экран и устанавливает цвет фона.
Но это, по крайней мере, даст вам результат процесса. замена print(output.decode('UTF-8')) покажет вам, что это за результат.
похоже, что программа застряла на этой строке кода "" "process = subprocess.Popen (cmd, stdout = subprocess.PIPE, stderr = subprocess.STDOUT)" "" после достижения этой строки программа начинает сохранять вывод в буферах и замолкает .. единственное, что я хочу извлечь из ngrok во время работы ngrok, - это перенаправленный URL-адрес, который предоставляет ngrok
@arslanmughal Вы частично правы, он не застрял в строке Popen(). Он застрял на print(process.stdout.readline()). Это большая разница, потому что это просто говорит нам, что Popen() не может получить результат процесса. Я также пробовал stdout.read(1), который ничего не возвращает. Поэтому я добавил дополнительный способ получения вывода.
Возможный дубликат Вывод на печать в реальном времени из подпроцесса. Хотя это просто вопрос, но он не будет работать для ngrok или другого приложения ncurses. Так что просто оставим это здесь для других, которые в конечном итоге здесь задаются вопросом, как получить вывод с
subprocess.