bashscriptは右矢印キーが押されたかどうかを検出します。

bashscriptは右矢印キーが押されたかどうかを検出します。

キーコードが右矢印キーでない場合でも常に真を検出するのはなぜですか?

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

答え1

(おそらく)最初に2バイト以上を読みました。$keycode矢印キーを押すと、スクリプトはESCになります。

矢印キーは次のとおりです。

\x1b + some value

条件式には空白がないため、常に真と評価されます。

編集:この声明を更新してください。

ifコマンドの終了状態に基づいて作業します[。この[コマンドはtest実際には同じです。注文するこれは非常に重要な事実です。コマンドとして引数の間にスペースが必要です。このコマンドのより特別な点は、最後のパラメータとして[必要であることです。]

[ EXPRESSION ]

コマンドはEXPRESSIONによって決定された状態で終了します。 1または0、本物または間違った

これはいいえかっこを書く奇妙な方法。つまりいいえ構文の一部(if例:C:)

if (x == 39)

通過:

if [ "$keycode"=39 ]; then

あなたは以下を発行します:

[ "$keycode"=39 ]

次に展開

[ \x1b=39 ]

ここでは、次のよう\x1b=39に読みます一つ議論。いつtestまたは[与えられたか一つパラメータがfalseで終了します。〜しない限りEXPRESSIONは空です。これは決して真実ではありません。$keycode空でも結果は=39(空ではない/null)です。

それを見るもう一つの方法は次のとおりです。

if 0 ; then # When _command_ exit with 0.
if 1 ; then # When _command_ exit with 1.

[詳細とvsに関する議論については、次の質問と回答を読んでください[[

これに関しては、バックティック対バックティックを見ることもできる。$( )


矢印キーを含むマルチバイトエスケープシーケンス:

上記のように:(おそらく)最初に2バイト以上を読みました。$keycode矢印キーを押すと、スクリプトはESCになります。

矢印やその他の特殊キーのためエスケープシーケンスシステムに送信します。これESCバイトシグナル「ここでは、異なる解釈が必要ないくつかのバイトが表示されます。」。矢印キーはASCII[の後にASCIIAまたはですBCD

つまり、矢印キーを処理するときに3バイトを解析する必要があります。

次の方向に確認してください。

{   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

生産する:

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

これがどのくらい移植性があるかはわかりませんが、このようなコードは以前に矢印キーをキャプチャするために使用されました。終了するにはタップします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

(小さめに、10進数と16進数が混在しているように見える10進数39についてもテストします。エスケープシーケンスの最初のバイトは次のとおりです。ASCII値ESC今すぐ少数27および16進数0x1b、一方少数39は16進数です0x27。 )

関連情報