使用陷阱和 Unix 信号读取 shell 中的按键

使用陷阱和 Unix 信号读取 shell 中的按键

我无法理解下面代码片段中的目的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),[:…:][.….]分别表示字符类和整理符号,反斜杠引用下一个\[或。]-

相关内容