Cancella stdin prima di leggere


14

Ho il seguente script bash:

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

Ora, come avrete intuito, se un utente preme alcuni tasti casuali durante il "compito che richiede tempo", viene preso in considerazione anche l'input indesiderato. Come posso cancellare stdin(o almeno ignorarlo) prima di emettere il comando read?


1
Io stesso, a meno che tu non stia scrivendo un programma simile a una maledizione, trovo che ciò che desideri fare sia un difetto di progettazione nel tuo programma. UNIX / Linux ha la caratteristica molto utile dell'input di buffering ("type-ahead") e comunemente uso questa funzionalità. Trovando il tuo programma dove butti via quello che ho digitato, probabilmente invierò un bug e smetterei di usare il tuo programma fino a quando non è stato risolto.
Arcege,

1
Alcuni utenti hanno la fastidiosa abitudine di suonare il piano con la tastiera mentre il loro programma è impegnato a fare qualcosa. Preferirei buttare via quei tasti e ricominciare da capo. Ma hai ragione, il "type-ahead" è utile, ma non sempre.
rabin,

Risposte:


8

Non penso che ci sia un modo per cancellare stdin ma (con bash) puoi leggere e scartare quello che c'è prima di chiedere l'input

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

Questo legge stdin e ha un timeout di 1 secondo, ma fallisce se ci sono più di 10000 caratteri nello stdin. Non so quanto sia grande il parametro nchars.


In realtà avevo trovato questo trucco su un forum. Mi aspettavo di trovare un modo migliore per farlo. Apparentemente no.
rabin,

@rabin: se trovi un modo migliore di postare qui, ce l'ho in alcuni script.

Sfortunatamente questo non funziona con tutte le shell, ad esempio trattino :(
scai

20

In Bash 4, è possibile impostare -t(timeout) su 0. In questo caso, readritorna immediatamente con uno stato di uscita che indica se ci sono dati in attesa o meno:

# 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

Questo legge più righe di input, se l'utente preme inavvertitamente inserire più volte


5

questo ha funzionato bene per me:

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

perché -ein questo caso?
nhed

@nhed non sono più sicuro, forse per aggirare qualche problema specifico del sistema
pschichtel,

4

Racchiudere l'attività che richiede tempo in un blocco il cui stdin è chiuso:

{
     # time consuming task
} <&-

read -p "Give me some input: " input

Credo che questo non abbia nulla a che fare con la domanda.
Scott,

Ma lo fa! L'utente desidera che tutti gli input vengano eliminati. Non consentire l'input fa esattamente questo - poiché lo stdin è chiuso, tutto l'input viene scartato (dal sistema). È una soluzione elegante al suo problema. Fa in modo che il sistema esegua lo scarto senza il problema di scrivere un ciclo di scarto.
HiTechHiTouch

Questa sembra essere l'opzione più affidabile finora.
Stephen Eilert,

Sembra perfetto ma non funziona per me. Ho provato bash 5.0.0 e 4.4.19. readleggerà comunque la prima riga inserita durante l' # time consumingattività. Inoltre, se lo script non contiene alcun comando che legge lo stdin dopo, le readlinee non lette vengono eseguite sul terminale interattivo al termine dello script. Qualcuno lo ha testato con successo?
Socowi,

4

Basandomi sulla risposta di christophjaeger, ho aggiunto in -smodo che l'input non venga ripetuto nel terminale e -nche non aspetti una nuova riga.

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

L'uso -nè una buona idea, ma due risposte precedenti l'hanno già menzionato. E dato che il punto di questo esercizio è leggere e scartare tutto ciò che è stato digitato prima che read fosse eseguito , non capisco a cosa pensi -sche farà.
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
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.