Динамический вывод из модуля подпроцесса python - PullRequest
0 голосов
/ 09 ноября 2018

Как я могу добиться вывода динамически с помощью модуля подпроцесса (пока внешняя программа продолжает работать) в Python.Внешняя программа, из которой я хочу получить вывод динамически: ngrok , ngrok продолжает работать до тех пор, пока работает моя программа, но мне нужен вывод во время работы процесса, чтобы я мог извлечь вновь сгенерированный "URL переадресации""

когда я пытаюсь сделать:

cmd = ['ngrok', 'http', '5000']
output = subprocess.Popen(cmd, stdout=subprocess.PIPE, buffersize=1)

, он продолжает хранить выходные данные в буферах

1 Ответ

0 голосов
/ 09 ноября 2018

Я знаю, что это дубликат, но сейчас я не могу найти соответствующие темы по этому поводу. Все, что я получаю, это 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')) покажет вам, что это за выход.

...