You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

伪终端运行的subprocess未适配真实终端全尺寸问题求解

解决方案

伪终端的窗口尺寸可以通过ioctl系统调用配合TIOCSWINSZ指令修改,Python的标准库fcntl模块可以直接调用该系统接口,同时可以监听终端尺寸变化信号实现动态适配。

完整修改后的代码

import os
import pty
import subprocess
import sys
import time
import select
import fcntl
import struct
import signal

# 终端尺寸操作相关ioctl指令,以下为Linux平台标准取值
TIOCGWINSZ = 0x5413
TIOCSWINSZ = 0x5414

def get_real_terminal_size():
    # 获取当前真实终端的行数、列数
    buf = struct.pack('HHHH', 0, 0, 0, 0)
    res = fcntl.ioctl(sys.stdout.fileno(), TIOCGWINSZ, buf)
    rows, cols, _, _ = struct.unpack('HHHH', res)
    return rows, cols

def set_pty_size(pty_fd, rows, cols):
    # 为指定伪终端文件描述符设置窗口尺寸
    buf = struct.pack('HHHH', rows, cols, 0, 0)
    fcntl.ioctl(pty_fd, TIOCSWINSZ, buf)

# 终端尺寸变化信号处理回调
def handle_sigwinch(signum, frame):
    rows, cols = get_real_terminal_size()
    # 同步更新两个伪终端的尺寸
    set_pty_size(stdout_master_fd, rows, cols)
    set_pty_size(stderr_master_fd, rows, cols)
    # 给子进程发送SIGWINCH信号,通知其适配新尺寸
    if p.poll() is None:
        os.kill(p.pid, signal.SIGWINCH)

# 注册SIGWINCH信号监听
signal.signal(signal.SIGWINCH, handle_sigwinch)

stdout_master_fd, stdout_slave_fd = pty.openpty()
stderr_master_fd, stderr_slave_fd = pty.openpty()

# 程序启动时先同步一次真实终端的初始尺寸
init_rows, init_cols = get_real_terminal_size()
set_pty_size(stdout_slave_fd, init_rows, init_cols)
set_pty_size(stderr_slave_fd, init_rows, init_cols)

p = subprocess.Popen(
    "top",
    shell=True,
    stdout=stdout_slave_fd,
    stderr=stderr_slave_fd,
    close_fds=True
)

stdout_parts = []
while p.poll() is None:
    rlist, _, _ = select.select([stdout_master_fd, stderr_master_fd], [], [])
    for f in rlist:
        output = os.read(f, 1000)  # 非阻塞读取
        sys.stdout.write(output.decode("utf-8"))
        sys.stdout.flush()
    time.sleep(0.01)

关键逻辑说明

  • 类Unix系统中终端尺寸通过winsize结构体存储,包含行数、列数、像素宽度、像素高度四个字段,常规场景下仅需要设置行数和列数即可适配字符输出
  • 程序启动时会先读取当前真实终端的尺寸,赋值给新建的两个伪终端,解决初始默认80x24尺寸不对的问题
  • 监听SIGWINCH信号,当用户拖拽终端改变大小时,会同步更新伪终端的尺寸,同时给子进程发送SIGWINCH信号,通知子进程重新渲染适配新尺寸

注意:上述TIOCGWINSZ和TIOCSWINSZ的取值为Linux平台的标准值,如果需要适配macOS等其他类Unix系统,可以通过对应系统的头文件查询指令的对应数值。

内容的提问来源于stack exchange,提问作者Mugen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.24 00:15:05