python子流程模块的动态输出
当外部程序在python中运行时,如何使用子流程模块动态实现输出。我想从中动态获取输出的外部程序是, 只要我的程序在运行,ngrok就会一直运行,但我需要在进程运行时输出,以便提取新生成的转发url 当我尝试这样做时:python子流程模块的动态输出,python,python-3.x,subprocess,ngrok,Python,Python 3.x,Subprocess,Ngrok,当外部程序在python中运行时,如何使用子流程模块动态实现输出。我想从中动态获取输出的外部程序是, 只要我的程序在运行,ngrok就会一直运行,但我需要在进程运行时输出,以便提取新生成的转发url 当我尝试这样做时: cmd = ['ngrok', 'http', '5000'] output = subprocess.Popen(cmd, stdout=subprocess.PIPE, buffersize=1) 它一直将输出存储在缓冲区中我知道这是一个副本,但我现在找不到任何与此相关的线
cmd = ['ngrok', 'http', '5000']
output = subprocess.Popen(cmd, stdout=subprocess.PIPE, buffersize=1)
它一直将输出存储在缓冲区中我知道这是一个副本,但我现在找不到任何与此相关的线程。我得到的只是输出。交流 下面是一个可能有用的片段:
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.
poll检查进程是否有退出代码。如果进程已死亡,则继续循环并打印进程标准输出中的任何内容
还有其他更好的方法,但这是我能给你的最低限度,不会很快变得复杂
例如,process.stdout.read可以与select.select结合使用,以在新行不足时实现更好的缓冲输出。因为如果\n从未出现,上述示例可能会挂起整个应用程序
这里有很多缓冲区陷阱,在进行类似这样的手动操作之前,您需要了解这些陷阱。否则,请改用process.communicate
编辑:为了绕过ngrok使用的I/O的限制,您可以使用pty.fork并通过os.read模块读取child的标准输出:
这里仍然有一个问题,我不太清楚这是什么或为什么。
我猜这个过程正在等待一个信号/刷新一些。
问题是,它只打印ncurses的第一个设置数据,这意味着它会擦除屏幕并设置背景色
但这至少会给你这个过程的输出。替换printoutput.decode'UTF-8'将向您显示该输出是什么。看起来程序卡在这一行代码中process=subprocess.Popencmd,stdout=subprocess.PIPE,stderr=subprocess.stdout到达这一行后,程序开始将输出存储在缓冲区中并保持沉默。。当ngrok运行时,我想从ngrok中提取的唯一内容是ngrok提供的向前的urlprovides@arslanmughal你部分正确,它没有卡在Popen线tho上。它卡在printprocess.stdout.readline上。这是一个巨大的不同,因为它告诉我们Popen无法从进程中获得输出。我还尝试了stdout.read1,它不返回任何内容。所以我增加了一个额外的获取输出的方法。可能是重复的。虽然这只是问题本身,但它不适用于ngrok或其他ncurses应用程序。所以,把这个留给其他人,他们最终想知道如何从子流程中获得输出。
#!/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()