如何在Python中实时读取终端输出?

1 投票
2 回答
1534 浏览
提问于 2025-04-17 07:20

我正在写一个Python程序,用来运行一个虚拟终端。目前我这样启动它:

import pexpect, thread

def create_input(child, scrollers, textlength=80, height=12):
    while 1:
        newtext = child.readline()
        print newtext

child = pexpect.spawn("bash", timeout=30000)

thread.start_new_thread(create_input,(child))

这样做是有效的,我可以通过child.send(command)发送命令给它。不过,我只能得到整行的输出。这就意味着,如果我启动像Nano或Links这样的程序,我在进程完成之前是看不到任何输出的。而且我输入的内容在按下回车之前也看不见。有办法在bash输出时逐个读取字符吗?

2 个回答

2

你需要把bash正在运行的程序的输出方式改成不缓存输出,而不是默认的行缓存。很多程序都有一个命令行选项,可以让输出变成不缓存的。

expect项目有一个工具叫做unbuffer,看起来可以让你得到所有bash的无缓存输出。我个人没有使用过这个工具,但在StackOverflow上还有其他回答也推荐过它:bash:强制执行的进程使用无缓存的标准输出

1

问题出在别的地方。如果你打开一个交互式的命令行窗口,通常会打开一个运行 bash、sh、csh 或其他类似程序的终端窗口。注意这里提到的“终端”!

在以前,我们会把终端连接到串口(telnet 也是这样,但它是通过网络连接),同样是提到“终端”。

即使是简单的终端也会响应一些特殊的 ESC 代码,用来报告它的类型、设置光标位置、颜色、清屏等等。

所以你是在启动一个有交互输出的子进程,但在这种设置下,除了通过 bash 启动参数外,没有其他方法能告诉这个 shell 和子进程是连接到一个终端的。

我建议你启用 telnetd,但只在本地(127.0.0.1)。在你的程序中,创建一个套接字并连接到 localhost:telnet,然后查找如何模拟一个合适的终端。如果程序是行模式的,那就没问题,但如果你要进入全屏编辑模式,你需要一个 80x24 或 132x24 的数组,或者你想要的其他大小来存储字符和颜色。你还需要能够在这个数组中上下移动行。

我没有查过,但我想不出在 Python 中没有 telnet 客户端的例子,而且应该也有终端模拟器的相关内容!

另一个好处是,如果 IP 连接丢失,telnet 会话会自动清理,避免出现“幽灵进程”。

Martijn

撰写回答