J'ai un script Shell qui dit essentiellement quelque chose comme
while true; do
read -r input
if ["$input" = "a"]; then
echo "hello world"
fi
done
C'est très bien, et bien, mais je viens de réaliser que le fait d'appuyer sur ENTER présente un sérieux problème dans cette situation. Ce dont j'ai besoin, c'est que le script réponde lorsqu'une touche est enfoncée, sans avoir à appuyer sur Entrée.
Existe-t-il un moyen d'obtenir cette fonctionnalité dans un script Shell?
read -rsn1
Attendez-vous à une seule lettre (et n'attendez pas la soumission) et soyez silencieux (ne réécrivez pas cette lettre).
donc l'extrait de travail final est le suivant:
#!/bin/bash
while true; do
read -rsn1 input
if [ "$input" = "a" ]; then
echo "hello world"
fi
done
Une autre façon de le faire, de manière non bloquante (je ne sais pas si c'est ce que vous voulez). Vous pouvez utiliser stty pour régler le temps de lecture minimum à 0. (peu dangereux si stty sane n'est pas utilisé après)
stty -icanon time 0 min 0
Ensuite, exécutez simplement votre boucle comme d'habitude. Pas besoin de -r.
while true; do
read input
if ["$input" = "a"]; then
echo "hello world"
fi
done
IMPORTANT! Après avoir terminé sans bloquer, vous devez vous rappeler de remettre stty à la normale en utilisant
stty sane
Si vous ne le faites pas, vous ne pourrez rien voir sur le terminal et il semblera se bloquer.
Vous voudrez probablement inclure un piège pour ctrl-C comme si le script était fermé avant de revenir à la normale, vous ne pourrez plus voir quoi que ce soit que vous tapez et il semblera que le terminal a gelé.
trap control_c SIGINT
control_c()
{
stty sane
}
P.S Aussi, vous voudrez peut-être mettre une instruction sleep dans votre script afin de ne pas utiliser tout votre CPU car cela fonctionnera en continu aussi vite que possible.
sleep 0.1
P.S.S Il semble que le problème de suspension ne se produise que lorsque j'avais utilisé -echo comme je le faisais, ce qui n'est probablement pas nécessaire. Je vais le laisser dans la réponse, car il est toujours bon de réinitialiser stty à sa valeur par défaut pour éviter de futurs problèmes. Vous pouvez utiliser -echo si vous ne voulez pas que ce que vous avez tapé apparaisse à l'écran.
Vous pouvez utiliser cette fonction getkey
:
getkey() {
old_tty_settings=$(stty -g) # Save old settings.
stty -icanon
Keypress=$(head -c1)
stty "$old_tty_settings" # Restore old settings.
}
Il désactive temporairement le "mode canonique" dans les paramètres du terminal (stty -icanon
) Puis renvoie l'entrée de "head" (un shell intégré) avec l'option -c1 qui renvoie UN octet d'entrée standard. Si vous n'incluez pas le "stty -icanon" alors le script fait écho à la lettre de la touche enfoncée et attend ensuite RETOUR (pas ce que nous voulons). "Head" et "stty" sont des commandes intégrées de Shell. Il est important de sauvegarder et de restaurer les anciens paramètres du terminal une fois que vous avez appuyé sur la touche.
Ensuite, getkey () peut être utilisé en combinaison avec une instruction "case / esac
" Pour une sélection interactive à partir d'une liste d'entrées: exemple:
case $Keypress in
[Rr]*) Command response for "r" key ;;
[Ww]*) Command response for "w" key ;;
[Qq]*) Quit or escape command ;;
esac
Cette combinaison getkey()/case-esac
peut être utilisée pour rendre de nombreux scripts Shell interactifs. J'espère que ça aide.
J'ai un moyen de le faire dans mon projet: https://sourceforge.net/p/playshell/code/ci/master/tree/source/keys.sh
Il lit une seule clé chaque fois que key_readonce est appelé. Pour les clés spéciales, une boucle d'analyse spéciale s'exécuterait pour pouvoir également les analyser.
C'est la partie cruciale de celui-ci:
if read -rn 1 -d '' "${T[@]}" "${S[@]}" K; then
KEY[0]=$K
if [[ $K == $'\e' ]]; then
if [[ BASH_VERSINFO -ge 4 ]]; then
T=(-t 0.05)
else
T=(-t 1)
fi
if read -rn 1 -d '' "${T[@]}" "${S[@]}" K; then
case "$K" in
\[)
KEY[1]=$K
local -i I=2
while
read -rn 1 -d '' "${T[@]}" "${S[@]}" "KEY[$I]" && \
[[ ${KEY[I]} != [[:upper:]~] ]]
do
(( ++I ))
done
;;
O)
KEY[1]=$K
read -rn 1 -d '' "${T[@]}" 'KEY[2]'
;;
[[:print:]]|$'\t'|$'\e')
KEY[1]=$K
;;
*)
__V1=$K
;;
esac
fi
fi
utils_implode KEY __V0