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

基于Python在Linux终端实现文本式分屏及实时命令输出读取

实现终端纯文本分屏双Shell环境

完全可以实现你要的纯文本分屏双提示符功能,核心是用curses库控制终端布局,结合subprocess管理交互式Shell进程,再用多线程处理实时IO交互。以下是具体实现思路和示例代码:

核心技术选型

  • curses: 用于终端UI布局,分割窗口为左右两个区域,处理终端输入输出的重定向
  • subprocess: 创建交互式Fish Shell进程,实时读写其标准输入/输出(替代os.system/os.popen,支持流式获取输出)
  • threading: 为每个分屏窗口单独启动IO线程,避免阻塞主进程

关键实现细节

  1. 创建交互式子进程
    用subprocess.Popen启动Fish,必须配置流式IO参数,确保能实时获取输出:

    import subprocess
    import os
    
    def start_shell():
        return subprocess.Popen(
            ["fish"],
            stdin=subprocess.PIPE,
            stdout=subprocess.PIPE,
            stderr=subprocess.STDOUT,
            text=True,
            bufsize=1,  # 行缓冲,实时输出
            preexec_fn=os.setsid  # 独立会话,避免Shell退出影响主进程
        )
    

    这样设置后,即使运行cmatrix这类持续输出的命令,也能通过stdout.readline()循环实时读取输出。

  2. 分屏窗口布局
    用curses初始化终端,分割窗口为左右两部分,中间用|分隔:

    import curses
    
    def init_windows(stdscr):
        # 关闭光标显示
        curses.curs_set(0)
        # 获取终端尺寸
        height, width = stdscr.getmaxyx()
        # 分割左右窗口,中间留1列显示分隔符
        left_win = curses.newwin(height, width//2, 0, 0)
        right_win = curses.newwin(height, width//2, 0, width//2 + 1)
        # 绘制分隔线
        for y in range(height):
            stdscr.addch(y, width//2, "|")
        stdscr.refresh()
        # 启用窗口的滚动和输入功能
        for win in [left_win, right_win]:
            win.scrollok(True)
            win.idlok(True)
            win.nodelay(True)  # 非阻塞读取输入
        return left_win, right_win
    
  3. 多线程处理IO交互
    为每个窗口启动两个线程:一个读取Shell输出并显示到窗口,一个读取用户输入并发送给Shell:

    import threading
    
    def read_output(win, proc):
        while proc.poll() is None:
            line = proc.stdout.readline()
            if line:
                win.addstr(line)
                win.refresh()
    
    def send_input(win, proc, active):
        while proc.poll() is None:
            if active[0] is win:
                try:
                    key = win.getch()
                    if key != -1:
                        proc.stdin.write(chr(key))
                        proc.stdin.flush()
                except Exception:
                    pass
    

    这里用active列表来跟踪当前激活的窗口,方便用户切换输入焦点。

  4. 主循环与焦点切换
    主进程负责监听全局输入(比如按Tab切换窗口),更新激活状态:

    def main(stdscr):
        left_win, right_win = init_windows(stdscr)
        left_proc = start_shell()
        right_proc = start_shell()
    
        # 跟踪当前激活窗口,用列表实现可变对象引用
        active = [left_win]
    
        # 启动IO线程
        threading.Thread(target=read_output, args=(left_win, left_proc), daemon=True).start()
        threading.Thread(target=read_output, args=(right_win, right_proc), daemon=True).start()
        threading.Thread(target=send_input, args=(left_win, left_proc, active), daemon=True).start()
        threading.Thread(target=send_input, args=(right_win, right_proc, active), daemon=True).start()
    
        # 主循环处理焦点切换
        while True:
            key = stdscr.getch()
            if key == ord('\t'):
                # 切换激活窗口
                active[0] = right_win if active[0] is left_win else left_win
                # 高亮激活窗口边框
                for win in [left_win, right_win]:
                    win.border() if win is active[0] else win.clear()
                    win.refresh()
            elif key == ord('q'):
                # 退出时终止子进程
                left_proc.terminate()
                right_proc.terminate()
                break
    
    if __name__ == "__main__":
        curses.wrapper(main)
    

注意事项

  • 运行前确保终端支持curses(Alacritty完全兼容)
  • 若遇到Shell提示符不显示的问题,可在Fish启动时设置TERM=xterm-256color,确保终端环境变量正确传递
  • 退出时用terminate()终止子进程,避免遗留僵尸进程

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 14:52:43