web-dev-qa-db-fra.com

Bash: Comment terminer une boucle infinie avec n'importe quelle touche enfoncée?

J'ai besoin d'écrire une boucle infinie qui s'arrête lorsqu'une touche est enfoncée.

Malheureusement, celui-ci ne boucle que lorsqu'une touche est enfoncée.

Des idées s'il vous plaît?

#!/bin/bash

count=0
while : ; do

    # dummy action
    echo -n "$a "
    let "a+=1"

    # detect any key  press
    read -n 1 keypress
    echo $keypress

done
echo "Thanks for using this script."
exit 0
24
janmartin

Vous devez mettre l’entrée standard en mode non bloquant. Voici un exemple qui fonctionne:

#!/bin/bash

if [ -t 0 ]; then stty -echo -icanon -icrnl time 0 min 0; fi

count=0
keypress=''
while [ "x$keypress" = "x" ]; do
  let count+=1
  echo -ne $count'\r'
  keypress="`cat -v`"
done

if [ -t 0 ]; then stty sane; fi

echo "You pressed '$keypress' after $count loop iterations"
echo "Thanks for using this script."
exit 0

Edit 2014/12/09: Ajoutez l'indicateur -icrnl à stty pour attraper correctement la clé de retour. Utilisez cat -v au lieu de read pour capturer l'espace.

Il est possible que cat lise plusieurs caractères s'il est alimenté assez rapidement; Si ce n'est pas le comportement souhaité, remplacez cat -v par dd bs=1 count=1 status=none | cat -v.

33
sam hocevar

read a un paramètre de délai d'expiration -t qui pourrait être utilisé. Effectuez une vérification non bloquante pour l’entrée, en vérifiant si le statut de retour est 0 et, le cas échéant, rompez avec la boucle.

-t timeout

Cause read expire et renvoie l'échec si une ligne complète d'entrée n'est pas lue dans un délai de timeout secondes. timeout peut être un nombre décimal avec une partie décimale après le point décimal. Cette option est effective uniquement si read lit les entrées d’un terminal, d’un canal ou d’un autre fichier spécial; cela n'a aucun effet lors de la lecture de fichiers normaux. Si timeout vaut 0, read renvoie le résultat si la saisie est disponible sur le descripteur de fichier spécifié, échec sinon . L'état de sortie est supérieur à 128 si le délai est dépassé.

7
Paul

Habituellement, cela ne me dérange pas de rompre une boucle infinie bash avec un simple CTRL-C. C'est la manière traditionnelle de terminer un tail -f par exemple.

2
mouviciel

Voici une autre solution. Cela fonctionne pour n'importe quelle touche appuyée, y compris espace, entrée, flèches, etc. 

Testé à Bash:

IFS=''
if [ -t 0 ]; then stty -echo -icanon raw time 0 min 0; fi
while [ -z "$key" ]; do
    read key
done
if [ -t 0 ]; then stty sane; fi
0
YSN