less类终端程序如何同时处理管道stdin与键盘交互输入
less 同时处理管道输入和键盘交互的实现逻辑
当你执行ifconfig | less这类管道命令时,shell 会将管道左侧ifconfig进程的标准输出,直接绑定到右侧less进程的标准输入(stdin)上,这时候 less 的 stdin 确实只承载管道传输的命令输出,不会收到键盘输入——less 也根本不会尝试从 stdin 读取交互指令。
它能实时响应键盘的核心机制非常直接:
- 所有运行在终端会话里的进程,都可以直接打开和当前会话绑定的控制终端设备文件
/dev/tty,这个文件不受 stdin/stdout 重定向、管道的影响,只要进程还在当前终端会话下,读写这个文件就等同于直接和终端交互:读这个文件可以拿到用户的键盘输入,写这个文件可以直接向终端输出内容。less 启动后如果检测到 stdin 不是终端(也就是被重定向到管道/文件了),就会主动打开/dev/tty作为交互输入输出的通道。 - 拿到
/dev/tty的文件描述符后,less 会先把这个终端设置为原始模式(raw mode):关闭终端默认的行缓冲、输入回显、信号自动触发等默认逻辑,保证用户每按一个键都能被程序立刻捕获,不需要等回车,也不会把按键内容默认打印到屏幕上打乱分页布局。 - 最后 less 会通过IO多路复用机制(类Unix系统下常用
select()/poll(),Linux下用epoll、BSD/macOS下用kqueue)同时监听两个输入源的可读事件:- 监听承载管道数据的 stdin:有新的管道内容传过来时,就把内容读入内存缓冲区,做解析、排版后准备展示
- 监听连接
/dev/tty的文件描述符:有用户按键输入时,就读取按键内容,解析成翻页、搜索、跳转、退出等对应操作,立刻更新界面状态
这套逻辑不是less独有的,所有需要在stdin被重定向时依然保持终端交互的程序,比如需要输入密码的sudo、passwd,都是通过直接操作/dev/tty实现的。你可以自己做个简单验证:执行cat /etc/passwd | less,这时候less的stdin完全被管道占用,你依然可以正常按q退出、按/搜索、用方向键翻页,所有交互输入都来自/dev/tty,和stdin没有关系。
内容的提问来源于stack exchange,提问作者Max Yankov
相关产品推荐
相关产品推荐

