python 子进程模块的动态输出
Dynamic output from python subprocess module
如何在 python 中使用子进程模块动态实现输出(而外部程序保持 运行)。我想从中动态获取输出的外部程序是 ngrok ,
ngrok keep 运行 只要我的程序是 运行 但我需要在进程是 运行 时输出,这样我就可以提取新生成的 "forwarding 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 and/or 将输出独占到它自己的 user/thread 就像 SSH 要求ssh user@host
.
时输入密码
process.poll()
检查进程是否有退出代码(如果它死了),如果没有,它继续循环并打印进程 stdout
.
的任何内容
还有其他(更好的)方法来解决这个问题,但这是我能给你的最低限度,而且不会很快变得复杂。
例如,process.stdout.read()
可以与 select.select()
结合使用,以在换行时获得更好的缓冲输出。因为如果 \n
永远不会出现,上面的示例可能会挂起您的整个应用程序。
这里有很多缓冲区陷阱,在您手动执行此类操作之前需要了解这些缓冲区陷阱。否则,请改用 process.communicate()
。
编辑:要避开 ngrok 使用的 I/O 的 hogging/limitation,您可以使用 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()
这里还有一个问题,我不太确定是什么或为什么会这样。
我猜这个过程正在等待 signal/flush 某种方式。
问题是它只打印 ncurses 的第一个 "setup data",这意味着它擦除屏幕并设置背景颜色。
但这至少会给你过程的输出。替换 print(output.decode('UTF-8'))
会告诉你输出是什么。
如何在 python 中使用子进程模块动态实现输出(而外部程序保持 运行)。我想从中动态获取输出的外部程序是 ngrok , ngrok keep 运行 只要我的程序是 运行 但我需要在进程是 运行 时输出,这样我就可以提取新生成的 "forwarding 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 and/or 将输出独占到它自己的 user/thread 就像 SSH 要求ssh user@host
.
process.poll()
检查进程是否有退出代码(如果它死了),如果没有,它继续循环并打印进程 stdout
.
还有其他(更好的)方法来解决这个问题,但这是我能给你的最低限度,而且不会很快变得复杂。
例如,process.stdout.read()
可以与 select.select()
结合使用,以在换行时获得更好的缓冲输出。因为如果 \n
永远不会出现,上面的示例可能会挂起您的整个应用程序。
这里有很多缓冲区陷阱,在您手动执行此类操作之前需要了解这些缓冲区陷阱。否则,请改用 process.communicate()
。
编辑:要避开 ngrok 使用的 I/O 的 hogging/limitation,您可以使用 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()
这里还有一个问题,我不太确定是什么或为什么会这样。
我猜这个过程正在等待 signal/flush 某种方式。
问题是它只打印 ncurses 的第一个 "setup data",这意味着它擦除屏幕并设置背景颜色。
但这至少会给你过程的输出。替换 print(output.decode('UTF-8'))
会告诉你输出是什么。