![使用陷阱和 Unix 信号读取 shell 中的按键](https://linux22.com/image/65085/%E4%BD%BF%E7%94%A8%E9%99%B7%E9%98%B1%E5%92%8C%20Unix%20%E4%BF%A1%E5%8F%B7%E8%AF%BB%E5%8F%96%20shell%20%E4%B8%AD%E7%9A%84%E6%8C%89%E9%94%AE.png)
我无法理解下面代码片段中的目的trap
和多次调用。stty
我希望有人能给我简要介绍一下正在发生的事情。
getkey() {
local stty="$(stty -g)"
trap "stty $stty; trap SIGINT; return 128" SIGINT
stty cbreak -echo
local key
while true; do
key=$(dd count=1 2>/dev/null) || return $?
if [ -z "$1" ] || [[ "$key" == [$1] ]]; then
break
fi
done
stty $stty
echo "$key"
return 0
}
答案1
local stty="$(stty -g)"
保存当前终端设置。stty $stty
,当函数正常返回和 SIGINT 时执行,恢复这些设置。
trap "stty $stty; trap SIGINT; return 128" SIGINT
如果函数被 SIGINT(按Ctrl+发送的信号C)中断,则恢复终端设置并返回 128。(为什么是 128?我想知道。通常信号的退出状态是 128 + 信号编号。)
stty cbreak -echo
禁用终端的粗略编辑功能(字符/单词/行擦除),并关闭键入字符时的回显。
key=$(dd count=1 2>/dev/null) || return $?
从终端最多读取 512 字节(count
是块的数量,默认块大小为 512 字节)。这有点奇怪:我认为目的是读取一个字节。由于dd
一旦至少有一个字节可用就会返回,因此如果用户正在打字,实际上这将返回单个字节,但如果程序正在输入击键或者系统速度很慢,则可能会读取更多字节。该代码的优点是,如果用户键入多字节字符,则组成该字符的所有字节都可能(但不保证)在循环迭代中被读取。
如果dd
返回非零状态,则表示读取错误或信号;该函数立即返回。终端设置未恢复,这是一个错误,尽管大多数时候错误可能是用户按下Ctrl+ C,在这种情况下终端设置被恢复,或者终端已经消失,在这种情况下重点是没有实际意义。
if [ -z "$1" ] || [[ "$key" == [$1] ]]; then break fi
如果读取的字节是函数参数中的字符之一,则退出循环。如果参数为空,任何字符都会终止循环。参数不完全是一个字符列表,它位于通配符字符集语法:首字母^
或反转集合,大多数位置的!
减号被解析为范围(例如0-9
),[:…:]
并[.….]
分别表示字符类和整理符号,反斜杠引用下一个\
、[
或。]
-