Bash:检测按键:如何读取特殊的十六进制键序列(如插入)以及为什么它是“\x1b\x5b\x32\x7e”(插入)?
Bash: detecting key-presses: how to read special key hex sequence(like Insert) and why it is '\x1b\x5b\x32\x7e'(Insert)?
在 Advanced Bash-Scripting Guide Section 5.2 Example 5-3. Detecting key-presses. The whole code can be viewed at detecting_key-presses.sh 一书中。在示例中,有一些我无法理解的代码片段。
第一个片段:
# Convert the separate home-key to home-key_num_7:
if [ "$key" = $'\x1b\x4f\x48' ]; then
key=$'\x1b\x5b\x31\x7e'
# Quoted string-expansion construct.
fi
# Convert the separate end-key to end-key_num_1.
if [ "$key" = $'\x1b\x4f\x46' ]; then
key=$'\x1b\x5b\x34\x7e'
fi
$'\x1b\x5b\x32\x7e') # Insert
echo Insert Key
;;
在上面的片段中,例如,当我按下 Home 键和 Insert 键时,
- 为什么它会为 Home 生成
\x1b\x4f\x48
个序列,为 Insert 生成 \x1b\x5b\x32\x7e
个序列?
- 而且评论说"Convert the separate home-key to home-key_num_7"和"Convert the separate end-key to end-key_num_1",转换,"key_num_7"和"key_num_1"是什么意思?
第二个片段:
unset K1 K2 K3
read -s -N1 -p "Press a key: "
K1="$REPLY"
read -s -N2 -t 0.001
K2="$REPLY"
read -s -N1 -t 0.001
K3="$REPLY"
key="$K1$K2$K3"
在上面的片段中,每次我按下一个键,
- 为什么要读取3个变量来构造一个关键的十六进制序列?
- 第二个
read -s -N2 -t 0.001
,为什么要指定-t
(超时)选项和-N2
(nchars)读取2个字符而不是1个?
问了几个问题...
脚本需要 转义序列 通过 特殊键 发送。在典型的键盘上,这些是所有具有名称或图形符号的键(例如 ←,表示左光标)。根据约定(没有适用的标准)这些键发送以escape[=开头的字符序列48=],第二个字符通常是 [
。对于这两个字符,十六进制代码分别为 0x1b
和 0x5b
(参见 ASCII table). The 0x4f
is the letter O
, and would be sent by a terminal's special keys in application mode .
您的 Home 和 End[ 发送的特定序列=53=] 键使用与其他一些特殊键略有不同的约定,称为 PC 风格 (请参阅 xterm FAQ Why can't I use the home/end keys? 作为背景)。显然,脚本的开发者决定通过确保 Home 和 [=42] 发送的序列的两个变体来解决与该 FAQ 相关的问题=]End 将被翻译成 VT220-style 序列。
最后一个问题问为什么要分开读取,使用分开的变量。这是因为由特殊密钥发送的字符序列可能会通过网络传输,并且比 read
操作所允许的时间更长。因此每次尝试只能读取序列的一部分。脚本收集片段并将它们组合成一个字符序列。
在 Advanced Bash-Scripting Guide Section 5.2 Example 5-3. Detecting key-presses. The whole code can be viewed at detecting_key-presses.sh 一书中。在示例中,有一些我无法理解的代码片段。
第一个片段:
# Convert the separate home-key to home-key_num_7:
if [ "$key" = $'\x1b\x4f\x48' ]; then
key=$'\x1b\x5b\x31\x7e'
# Quoted string-expansion construct.
fi
# Convert the separate end-key to end-key_num_1.
if [ "$key" = $'\x1b\x4f\x46' ]; then
key=$'\x1b\x5b\x34\x7e'
fi
$'\x1b\x5b\x32\x7e') # Insert
echo Insert Key
;;
在上面的片段中,例如,当我按下 Home 键和 Insert 键时,
- 为什么它会为 Home 生成
\x1b\x4f\x48
个序列,为 Insert 生成\x1b\x5b\x32\x7e
个序列? - 而且评论说"Convert the separate home-key to home-key_num_7"和"Convert the separate end-key to end-key_num_1",转换,"key_num_7"和"key_num_1"是什么意思?
第二个片段:
unset K1 K2 K3
read -s -N1 -p "Press a key: "
K1="$REPLY"
read -s -N2 -t 0.001
K2="$REPLY"
read -s -N1 -t 0.001
K3="$REPLY"
key="$K1$K2$K3"
在上面的片段中,每次我按下一个键,
- 为什么要读取3个变量来构造一个关键的十六进制序列?
- 第二个
read -s -N2 -t 0.001
,为什么要指定-t
(超时)选项和-N2
(nchars)读取2个字符而不是1个?
问了几个问题...
脚本需要 转义序列 通过 特殊键 发送。在典型的键盘上,这些是所有具有名称或图形符号的键(例如 ←,表示左光标)。根据约定(没有适用的标准)这些键发送以escape[=开头的字符序列48=],第二个字符通常是 [
。对于这两个字符,十六进制代码分别为 0x1b
和 0x5b
(参见 ASCII table). The 0x4f
is the letter O
, and would be sent by a terminal's special keys in application mode .
您的 Home 和 End[ 发送的特定序列=53=] 键使用与其他一些特殊键略有不同的约定,称为 PC 风格 (请参阅 xterm FAQ Why can't I use the home/end keys? 作为背景)。显然,脚本的开发者决定通过确保 Home 和 [=42] 发送的序列的两个变体来解决与该 FAQ 相关的问题=]End 将被翻译成 VT220-style 序列。
最后一个问题问为什么要分开读取,使用分开的变量。这是因为由特殊密钥发送的字符序列可能会通过网络传输,并且比 read
操作所允许的时间更长。因此每次尝试只能读取序列的一部分。脚本收集片段并将它们组合成一个字符序列。