python - python subprocess 模块的动态输出

标签 python python-3.x subprocess ngrok

如何在Python中使用子进程模块(当外部程序保持运行时)动态实现输出。我想从中动态获取输出的外部程序是 ngrok , 只要我的程序正在运行,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 使用的 I/O 占用/限制,您可以使用 pty.fork()并通过os.read读取 child 的标准输出模块:

#!/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'))会告诉你输出是什么。

关于python - python subprocess 模块的动态输出,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53229305/

相关文章:

python - 在 Python 请求中使用 cookies.txt 文件

Python 基础 - 为什么我的文件内容不打印?

python - 用 Python 读取文本文件并从中选择类别

python - 查找 Pandas 中每列的每个唯一值的百分比

python - execveat(2)/fexecve(3) 类似于 Python 子进程的行为

python - Groupby 连续行中的累积运算 pandas

Python与C交互——回调函数

python - PyGObject 与 GStreamer 示例?

python - 将变量传递给子流程调用

python subprocess.call 和管道