Effacer stdin avant de lire


14

J'ai le script bash suivant:

# do some time consuming task here
read -p "Give me some input: " input

Maintenant, comme vous l'avez peut-être deviné, si un utilisateur appuie sur des touches aléatoires pendant la "tâche longue", l'entrée indésirable est également prise en compte. Comment effacer stdin(ou au moins l'ignorer) avant d'émettre la commande de lecture?


1
Moi-même, à moins que vous n'écriviez un programme de type malédiction, je trouve que ce que vous souhaitez faire est un défaut de conception dans votre programme. UNIX / Linux possède la fonctionnalité très utile de mise en mémoire tampon des entrées ("type-ahead") et j'utilise couramment cette fonctionnalité. En rencontrant votre programme où vous jetez ce que j'ai tapé, je soumettrais probablement un bogue et cesserais d'utiliser votre programme jusqu'à ce qu'il soit corrigé.
Arcege

1
Certains utilisateurs ont la fâcheuse habitude de jouer du piano avec leur clavier pendant que leur programme est occupé à faire quelque chose. Je préfère jeter ces touches et recommencer à zéro. Mais vous avez raison, le "type-ahead" est utile, mais pas toujours.
rabin

Réponses:


8

Je ne pense pas qu'il y ait un moyen d'effacer stdin mais (avec bash) vous pouvez lire et jeter ce qui est là avant de demander l'entrée

#do some time consuming task here
read -t 1 -n 10000 discard 
read -p "Give me some input: " input

Cela lit stdin et a un délai d'attente de 1 seconde, mais il échoue s'il y a plus de 10000 caractères dans stdin. Je ne sais pas quelle taille vous pouvez faire pour le paramètre nchars.


En fait, j'avais trouvé ce hack sur un forum. Je m'attendais à trouver une meilleure façon de le faire. Apparemment non.
rabin

@rabin: Si vous trouvez un meilleur moyen de poster ici, je l'ai dans quelques scripts.

Malheureusement, cela ne fonctionne pas avec tous les shells, par exemple dash :(
scai

20

Dans Bash 4, vous pouvez définir -t(timeout) sur 0. Dans ce cas, readretourne immédiatement avec un état de sortie indiquant s'il y a des données en attente ou non:

# do some time consuming task here
while read -r -t 0; do read -r; done
read -p "Give me some input: " input

6
read -d '' -t 0.1 -n 10000

Cela lit plusieurs lignes d'entrées, si l'utilisateur a appuyé par inadvertance sur plusieurs fois


5

cela a bien fonctionné pour moi:

function clean_stdin()
{
    while read -e -t 0.1; do : ; done
}

pourquoi -edans ce cas?
nhed le

@nhed ne sais plus, peut-être pour contourner un problème spécifique au système
pschichtel

4

Mettez la tâche longue dans un bloc dont stdin est fermé:

{
     # time consuming task
} <&-

read -p "Give me some input: " input

Je pense que cela n'a rien à voir avec la question.
Scott

Mais c'est le cas! L'utilisateur souhaite que toutes les entrées soient supprimées. Ne pas autoriser l'entrée fait exactement cela - puisque stdin est fermé, toutes les entrées sont rejetées (par le système). C'est une solution élégante à son problème. Il obtient le système pour effectuer la suppression sans avoir à écrire une boucle de suppression.
HiTechHiTouch

Cela semble être l'option la plus fiable jusqu'à présent.
Stephen Eilert

Semble parfait mais ne fonctionne pas pour moi. J'ai essayé bash 5.0.0 et 4.4.19. readlira toujours la première ligne entrée pendant la # time consumingtâche. De plus, si le script ne contient aucune commande lisant stdin après le, readles lignes non lues sont exécutées sur le terminal interactif une fois le script terminé. Quelqu'un a-t-il réussi à tester cela?
Socowi

4

En me basant sur la réponse de christophjaeger, j'ai ajouté -spour que l'entrée ne soit pas répercutée sur le terminal et -npour qu'il n'attende pas une nouvelle ligne.

while read -r -t 0; do
    read -n 256 -r -s
done

L'utilisation -nest une bonne idée, mais deux réponses précédentes l'ont déjà mentionné. Et étant donné que le but de cet exercice est de lire et de jeter tout ce qui a été tapé avant l' read exécution , je ne comprends pas à quoi vous pensez que cela -sva faire du bien.
Scott

2
function clear_stdin()
(
    old_tty_settings=`stty -g`
    stty -icanon min 0 time 0

    while read none; do :; done 

    stty "$old_tty_settings"
)

clear_stdin
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.