基于Python在Linux终端实现文本式分屏及实时命令输出读取
实现终端纯文本分屏双Shell环境
完全可以实现你要的纯文本分屏双提示符功能,核心是用curses库控制终端布局,结合subprocess管理交互式Shell进程,再用多线程处理实时IO交互。以下是具体实现思路和示例代码:
核心技术选型
curses: 用于终端UI布局,分割窗口为左右两个区域,处理终端输入输出的重定向subprocess: 创建交互式Fish Shell进程,实时读写其标准输入/输出(替代os.system/os.popen,支持流式获取输出)threading: 为每个分屏窗口单独启动IO线程,避免阻塞主进程
关键实现细节
创建交互式子进程
用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()循环实时读取输出。分屏窗口布局
用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多线程处理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列表来跟踪当前激活的窗口,方便用户切换输入焦点。主循环与焦点切换
主进程负责监听全局输入(比如按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
相关产品推荐
相关产品推荐

