Você (provavelmente) lê primeiro dois bytes +. $keycode
no seu script seria ESC quando a tecla de seta é pressionada.
As teclas de seta podem ser:
\x1b + some value
Ele sempre é avaliado como verdadeiro devido à falta de espaços na expressão condicional.
Edit: uma atualização nessa declaração.
Seu if
opera no status de saída do comando [
. O comando [
é equivalente a test
. O fato de ser um comando é um fato muito importante. Como um comando, requer espaços entre argumentos. O comando [
é ainda mais especial porque requer ]
como último argumento.
[ EXPRESSION ]
O comando sai com o status determinado por EXPRESSION. 1 ou 0, true ou falso .
Não é uma maneira exótica de escrever parênteses. Em outras palavras, não é parte da sintaxe if
como, por exemplo, em C:
if (x == 39)
Por:
if [ "$keycode"=39 ]; then
você emite:
[ "$keycode"=39 ]
que se expande para
[ \x1b=39 ]
aqui \x1b=39
é lido como um argumento um . Quando test
ou [
recebe o argumento um , ele sai com falso somente se EXPRESSION for nulo - o que nunca será. Mesmo se $keycode
estivesse vazio, resultaria em =39
(que não é nulo / vazio).
Outra maneira de ver isso é que você diz:
if 0 ; then # When _command_ exit with 0.
if 1 ; then # When _command_ exit with 1.
Leia estas perguntas e respostas para obter mais detalhes - bem como a discussão sobre [
vs [[
:
Nesse sentido, você também pode pesquisar carrapatos de volta '' vs $( )
Sequência de escape multibyte com teclas de seta:
Como mencionado no topo: Você (provavelmente) lê primeiro dois bytes +. $keycode
no seu script seria ESC quando a tecla de seta é pressionada.
Seta e outras chaves especiais resultam em seqüências de escape a serem enviadas para o sistema. O ESC byte sinaliza que "aqui vem alguns bytes que devem ser interpretados de forma diferente" . Quanto às teclas de seta que seriam ASCII [
seguido por ASCII A
, B
, C
ou D
.
Em outras palavras, você precisa analisar três bytes ao lidar com as teclas de seta.
Você pode tentar algo na direção disso para verificar:
{ 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
Rendimento:
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
Não tenho certeza de como isso é portátil, mas já usei códigos como esse para capturar as teclas de seta. Pressione q
para sair:
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
(Como nota menor, você também (pretende) testar contra o decimal 39 - que se parece com uma mistura entre decimal e hexadecimal. Primeiro byte em uma seqüência de escape é Valor ASCII ESC , que é decimal 27 e hexadecimal 0x1b
, enquanto decimal 39 é hexadecimal 0x27
.)