bashscript 检测被按下的右箭头键

Con*_*ack 9 bash shell-script

为什么即使键码不是右箭头键,这也总是检测为真?

stty_state=`stty -g`
stty raw; stty -echo
keycode=`dd bs=1 count=1 2>/dev/null`
stty "$stty_state"  

echo $keycode

if [ "$keycode"=39 ]; then
echo "Right Arrow Key Pressed!"
fi
Run Code Online (Sandbox Code Playgroud)

use*_*890 17

您(可能)首先读取了两个以上的字节。$keycode按下箭头键时,您的脚本中将是 ESC 。

箭头键可以是:

\x1b + some value
Run Code Online (Sandbox Code Playgroud)

由于条件表达式中缺少空格,它总是评估为真。

编辑:该声明的更新。

if[命令的退出状态进行操作。该[命令等效于test. 它是一个命令这一事实是一个非常重要的事实。作为命令,它在参数之间需要空格。该[命令更特殊,因为它需要]作为最后一个参数。

[ EXPRESSION ]
Run Code Online (Sandbox Code Playgroud)

该命令以 EXPRESSION 确定的状态退出。1 或 0,

不是一种写括号的奇特方式。换句话说,它不是if语法的一部分,例如在 C 中:

if (x == 39)
Run Code Online (Sandbox Code Playgroud)

经过:

if [ "$keycode"=39 ]; then
Run Code Online (Sandbox Code Playgroud)

你发出:

[ "$keycode"=39 ]
Run Code Online (Sandbox Code Playgroud)

扩展到

[ \x1b=39 ]
Run Code Online (Sandbox Code Playgroud)

这里\x1b=39被视为一个论点。当testor[被赋予一个参数时,仅当EXPRESSION 为 null 时它才会以 false 退出——这是永远不会的。即使$keycode是空的,也会导致=39(非空/空)。

另一种看待它的方式是你说:

if 0 ; then # When _command_ exit with 0.
if 1 ; then # When _command_ exit with 1.
Run Code Online (Sandbox Code Playgroud)

阅读这些问题和答案以获取更多详细信息——以及关于[vs 的讨论[[

在这方面,您还可以研究回拨`` vs $( )


带箭头键的多字节转义序列:

如顶部所述:您(可能)首先读取了两个以上的字节。$keycode按下箭头键时,您的脚本中将是 ESC 。

箭头和其他特殊键会导致将转义序列发送到系统。该ESC字节的信号是“这里来一些字节应该以不同的解释”。至于箭头键这将是ASCII[其次是ASCII ABCD

换句话说,您在处理箭头键时必须解析三个字节。

您可以尝试朝这个方向进行一些检查:

{   stty_state=$(stty -g)
    stty raw isig -echo
    keycode=$(dd bs=8 conv=sync count=1)
    stty "$stty_state"
} </dev/tty 2>/dev/null
printf %s "$keycode" | xxd
Run Code Online (Sandbox Code Playgroud)

屈服:

HEX        ASCII
1b 5b 41   .[A # Up arrow
1b 5b 42   .[B # Down arrow
1b 5b 43   .[C # Right arrow
1b 5b 44   .[D # Left arrow
 |  |  |
 |  |  +------ ASCII A, B, C and D
 |  +--------- ASCII [
 +------------ ASCII ESC
Run Code Online (Sandbox Code Playgroud)

不确定这有多便携,但之前曾使用过这样的代码来捕捉箭头键。按q退出:

while read -rsn1 ui; do
    case "$ui" in
    $'\x1b')    # Handle ESC sequence.
        # Flush read. We account for sequences for Fx keys as
        # well. 6 should suffice far more then enough.
        read -rsn1 -t 0.1 tmp
        if [[ "$tmp" == "[" ]]; then
            read -rsn1 -t 0.1 tmp
            case "$tmp" in
            "A") printf "Up\n";;
            "B") printf "Down\n";;
            "C") printf "Right\n";;
            "D") printf "Left\n";;
            esac
        fi
        # Flush "stdin" with 0.1  sec timeout.
        read -rsn5 -t 0.1
        ;;
    # Other one byte (char) cases. Here only quit.
    q) break;;
    esac
done
Run Code Online (Sandbox Code Playgroud)

(作为一个小提示,您还(打算)针对十进制 39 进行测试——这看起来像是十进制和十六进制之间的混合。转义序列中的第一个字节是ASCII 值 ESC,它是十进制27 和十六进制0x1b,而十进制39 是十六进制0x27。 )

  • 问题中的第一个问题是测试中的 `=` 符号周围没有空格,因此它被简单地解析为非空字符串,因此为真。箭头键是多个字节的事实是一个单独的问题。 (2认同)
  • 嗯,这句话没有太多的上下文,我读了一遍,因为我认为这是我已经知道的多字节序列解释的一部分。 (2认同)
  • @wurtel:是的。我猜是模糊的。发现一旦解释了`[` 是一个内置的*命令*,人们就会更快地理解为什么空格很重要。(使用方括号而不是圆括号不仅仅是 bash 的一种奇怪方式。)现在必须用完。回来更新一次。 (2认同)