如何在Bash脚本中捕获特殊按键及普通单字符输入
问题根因
原有代码存在两处设计错误,直接导致功能不符合预期:
- 固定顺序执行两次
read调用,分别强制读取2个字符、1个字符,必须凑满3个输入字符才会进入后续判断逻辑,单字节长度的普通字符、回车、Tab等按键自然无法触发输出 - 未针对终端按键的编码特征做分支处理:方向键等扩展特殊按键是以
\e(ESC,ASCII码27)开头的3字节转义序列,回车、空格、Tab、普通字符都是单字节编码,原有逻辑没有区分两类输入结构,既无法正确捕获单字节按键,也无法区分回车和空格这类编码不同的单字节按键。
可运行实现代码
#!/bin/bash # 保存终端原始配置,脚本退出时自动恢复,避免终端状态异常 old_tty_settings=$(stty -g) trap 'stty "$old_tty_settings"; exit 0' INT TERM EXIT # 关闭终端行缓冲、关闭输入回显,实现按键按下即时读取 stty raw -echo # 读取第一个输入字节 IFS= read -rsn1 first_char if [[ $first_char == $'\e' ]]; then # 首字节是ESC,说明是特殊按键转义序列,读取后续2个字节,加0.1s超时避免单独按ESC时永久卡住 IFS= read -rsn2 -t 0.1 seq_suffix case $seq_suffix in '[A') echo "检测到按键:上方向键(UP_ARROW)" ;; '[B') echo "检测到按键:下方向键(DOWN_ARROW)" ;; '[C') echo "检测到按键:右方向键(RIGHT_ARROW)" ;; '[D') echo "检测到按键:左方向键(LEFT_ARROW)" ;; *) echo "检测到其他转义类特殊按键" ;; esac else # 单字节按键,直接按编码匹配类型 case $first_char in $'\n'|$'\r') echo "检测到按键:回车(ENTER)" ;; $'\t') echo "检测到按键:制表符(TAB)" ;; ' ') echo "检测到按键:空格(SPACE)" ;; [a-zA-Z0-9!-\?]) echo "检测到普通字符输入:$first_char" ;; *) echo "检测到其他单字节按键" ;; esac fi # 执行结束恢复终端默认配置 stty "$old_tty_settings"
关键逻辑说明
- 终端默认开启行缓冲模式,必须等按下回车才会把输入内容传给程序,通过
stty raw可以关闭行缓冲,实现按键即时捕获 trap配置是必须项,否则脚本被Ctrl+C中断、异常报错退出时,终端会保持无回显、无行缓冲的异常状态,无法正常输入命令- 转义序列读取加0.1秒短超时,是为了兼容单独按下ESC键的场景,不会永久阻塞等待后续输入
- 所有单字节按键通过ASCII码精确匹配,可以100%区分回车、空格、Tab和普通字符,不会出现识别混淆。
内容的提问来源于stack exchange,提问作者Random Guy
相关产品推荐
相关产品推荐

