gpt4 book ai didi

python - 从 pty 中读取而不会无休止地挂起

转载 作者:行者123 更新时间:2023-11-28 22:30:52 27 4
gpt4 key购买 nike

我有一个脚本,如果它在 tty 上,它会打印彩色输出。他们中的一堆并行执行,所以我不能把他们的标准输出到 tty。我也无法控制脚本代码(强制着色),所以我想通过 pty 伪造它。我的代码:

invocation = get_invocation()
master, slave = pty.openpty()
subprocess.call(invocation, stdout=slave)
print string_from_fd(master)

而且我不知道 string_from_fd 中应该有什么。现在,我有类似的东西

def string_from_fd(fd):
return os.read(fd, 1000)

它有效,但是那个数字 1000 看起来很奇怪。我认为输出可以非常大,任何数量都不够。我尝试了很多来自堆栈溢出的解决方案,但没有一个有效(它不打印任何内容或永远挂起)。

我对文件描述符之类的不是很熟悉,所以如果我做错了什么,任何澄清都将不胜感激。

谢谢!

最佳答案

这不适用于长输出:subprocess.call 将在 PTY 的缓冲区已满时阻塞。这就是为什么 subprocess.communicate存在,但这不适用于 PTY。

标准/最简单的解决方案是使用外部模块 pexpect ,它在内部使用 PTY:例如,

pexpect.spawn("/bin/ls --color=auto").read()

将为您提供带颜色代码的 ls 输出。

如果您想坚持使用 subprocess,那么您必须使用 subprocess.Popen,原因如上所述。您的假设是正确的,通过传递 1000,您最多读取 1000 个字节,因此您必须使用循环。 os.read 如果没有可读取的内容就会阻塞并等待数据出现。问题在于如何识别进程何时终止:在这种情况下,您知道不会再有数据到达。对 os.read 的下一次调用将永远阻塞。幸运的是,操作系统可以帮助您检测到这种情况:如果可以用于写入的伪终端的所有文件描述符都已关闭,那么 os.read 将返回一个空字符串或返回一个错误,取决于操作系统。您可以检查这种情况并在这种情况发生时退出循环。现在理解以下代码的最后一部分是理解打开的文件描述符和 subprocess 是如何结合在一起的: subprocess.Popen 在内部调用 fork() ,它复制当前进程,包括所有打开的文件描述符,然后在两个执行路径之一中调用 exec(),它终止当前进程以支持新进程。在另一个执行路径中,控制权返回到您的 Python 脚本。因此在调用 subprocess.Popen 之后,有 两个 有效的文件描述符用于 PTY 的从属端:一个属于生成的进程,一个属于您的 Python 脚本。如果你关闭你的,那么唯一可用于将数据发送到主端的文件描述符属于衍生进程。在它终止时,它被关闭,PTY 进入状态,在 master 端调用 read 失败。

代码如下:

import os
import pty
import subprocess

master, slave = pty.openpty()
process = subprocess.Popen("/bin/ls --color", shell=True, stdout=slave,
stdin=slave, stderr=slave, close_fds=True)
os.close(slave)

output = []
while True:
try:
data = os.read(master, 1024)
except OSError:
break
if not data:
break
output.append(data) # In Python 3, append ".decode()" to os.read()
output = "".join(output)

关于python - 从 pty 中读取而不会无休止地挂起,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41921095/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com