Borrar stdin antes de leer

14

Tengo el siguiente script bash:

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

Ahora, como habrás adivinado, si un usuario presiona algunas teclas aleatorias durante la "tarea que consume mucho tiempo", la entrada no deseada también se tiene en cuenta. ¿Cómo borro stdin(o al menos lo ignoro) antes de emitir el comando de lectura?

rabin
fuente
1
Yo mismo, a menos que esté escribiendo un programa tipo maldición, encuentro que lo que desea hacer es ser un defecto de diseño en su programa. UNIX / Linux tiene la característica muy útil de almacenar en búfer la entrada ("escritura anticipada") y comúnmente uso esta funcionalidad. Al encontrarme con su programa donde tira lo que escribí, es probable que envíe un error y deje de usar su programa hasta que se solucione.
Arcege
1
Algunos usuarios tienen la molesta costumbre de tocar el piano con su teclado mientras su programa está ocupado haciendo algo. Prefiero tirar esas teclas y empezar de nuevo. Pero tienes razón, la "escritura anticipada" es útil, pero no siempre.
rabin

Respuestas:

8

No creo que haya una manera de borrar stdin pero (con bash) puedes leer y descartar lo que hay antes de pedir la entrada

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

Esto lee stdin y tiene un tiempo de espera de 1 segundo, aunque falla si hay más de 10000 caracteres en stdin. No sé qué tan grande puedes hacer el parámetro nchars.


fuente
En realidad, encontré este truco en un foro. Esperaba encontrar una mejor manera de hacerlo. Aparentemente no.
rabin
@rabin: Si encuentra una mejor manera de publicar aquí, lo tengo en unos pocos guiones.
Desafortunadamente, esto no funciona con todos los shells, por ejemplo, guión :(
scai
20

En Bash 4, puede establecer -t(tiempo de espera) en 0. En este caso, readregresa inmediatamente con un estado de salida que indica si hay datos en espera o no:

# do some time consuming task here
while read -r -t 0; do read -r; done
read -p "Give me some input: " input
christophjaeger
fuente
6
read -d '' -t 0.1 -n 10000

Esto lee múltiples líneas de entradas, si el usuario presionó inadvertidamente ingresar varias veces

Ram Natarajan
fuente
5

esto funcionó bien para mí:

function clean_stdin()
{
    while read -e -t 0.1; do : ; done
}
pschichtel
fuente
¿Por qué -een este caso?
nhed
@nhed no seguro de nada, tal vez para eludir algún problema específico del sistema
pschichtel
4

Adjunte la tarea que consume tiempo en un bloque cuyo stdin está cerrado:

{
     # time consuming task
} <&-

read -p "Give me some input: " input
artistoex
fuente
Creo que esto no tiene nada que ver con la pregunta.
Scott
Pero lo hace! El usuario quiere que se descarten todas las entradas. No permitir la entrada hace exactamente eso: dado que stdin está cerrado, toda la entrada se descarta (por el sistema). Es una solución elegante a su problema. Él consigue que el sistema haga el descarte sin la molestia de escribir un ciclo de descarte.
HiTechHiTouch
Esta parece ser la opción más confiable hasta ahora.
Stephen Eilert
Parece perfecto pero no funciona para mí. Intenté bash 5.0.0 y 4.4.19. readseguirá leyendo la primera línea ingresada durante la # time consumingtarea. Además, si el script no contiene ningún comando que lea stdin después de readeso, las líneas no leídas se ejecutan en el terminal interactivo después de que finaliza el script. ¿Alguien probó con éxito esto?
Socowi
4

Sobre la base de la respuesta de Christophjaeger, agregué -spara que la entrada no se repita en la terminal y -npara que no espere una nueva línea.

while read -r -t 0; do
    read -n 256 -r -s
done
Peter Sutton
fuente
Usar -nes una buena idea, pero dos respuestas anteriores ya lo han mencionado. Y dado que el objetivo de este ejercicio es leer y descartar todo lo que se escribió antes de su read ejecución , no entiendo qué bien cree -sque va a hacer.
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
Илья Антипов
fuente