Hapus stdin sebelum membaca

14

Saya memiliki skrip bash berikut:

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

Sekarang seperti yang sudah Anda duga, jika pengguna menekan beberapa kunci acak selama "tugas yang memakan waktu", input yang tidak diinginkan juga diperhitungkan. Bagaimana saya menghapus stdin(atau setidaknya mengabaikannya) sebelum saya mengeluarkan perintah baca?

rabin
sumber
1
Saya sendiri, kecuali Anda menulis program seperti kutukan, saya menemukan apa yang ingin Anda lakukan untuk menjadi cacat desain dalam program Anda. UNIX / Linux memiliki fitur input buffering ("type-ahead") yang sangat berguna dan saya biasanya menggunakan fungsi ini. Melihat program Anda di mana Anda membuang apa yang saya ketikkan, saya kemungkinan akan mengirimkan bug dan berhenti menggunakan program Anda sampai diperbaiki.
Arcege
1
Beberapa pengguna memiliki kebiasaan mengganggu bermain piano dengan keyboard mereka sementara program mereka sibuk melakukan sesuatu. Saya lebih suka membuang penekanan tombol itu dan mulai segar. Tapi Anda benar, "tipe-depan" berguna, tetapi tidak selalu.
rabin

Jawaban:

8

Saya tidak berpikir ada cara untuk menghapus stdin tetapi (dengan bash) Anda dapat membaca dan membuang apa yang ada sebelum Anda meminta input

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

Ini berbunyi stdin dan memiliki batas waktu 1 detik, namun gagal jika ada lebih dari 10.000 karakter di stdin. Saya tidak tahu seberapa besar Anda bisa membuat parameter nchars.


sumber
Saya sebenarnya menemukan retasan ini di sebuah forum. Saya berharap menemukan cara yang lebih baik untuk melakukannya. Sepertinya tidak.
rabin
@ rabin: Jika Anda menemukan cara posting yang lebih baik di sini saya memilikinya dalam beberapa skrip.
Sayangnya ini tidak bekerja dengan semua kerang, misalnya dasbor :(
AKSI
20

Di Bash 4, Anda dapat mengatur -t(batas waktu) menjadi 0. Dalam hal ini, readsegera kembali dengan status keluar yang menunjukkan apakah ada data yang menunggu atau tidak:

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

Ini berbunyi beberapa baris input, jika pengguna secara tidak sengaja menekan masukkan beberapa kali

Ram Natarajan
sumber
5

ini bekerja dengan baik untuk saya:

function clean_stdin()
{
    while read -e -t 0.1; do : ; done
}
pschichtel
sumber
mengapa -edalam hal ini?
nhed
@nhed tidak yakin lagi, mungkin untuk menghindari beberapa masalah khusus sistem
pschichtel
4

Lampirkan tugas yang memakan waktu di blok yang stdinnya ditutup:

{
     # time consuming task
} <&-

read -p "Give me some input: " input
artisoex
sumber
Saya percaya bahwa ini tidak ada hubungannya dengan pertanyaan.
Scott
Tapi itu benar! Pengguna ingin semua input dibuang. Tidak mengizinkan input melakukan hal itu - karena stdin ditutup, semua input dibuang (oleh sistem). Ini solusi elegan untuk masalahnya. Dia mendapatkan sistem untuk melakukan discard tanpa kesulitan menulis loop discard.
HiTechHiTouch
Ini tampaknya menjadi opsi yang paling dapat diandalkan sejauh ini.
Stephen Eilert
Tampak sempurna tetapi tidak bekerja untuk saya. Saya mencoba bash 5.0.0 dan 4.4.19. readakan tetap membaca baris pertama yang dimasukkan selama # time consumingtugas. Selanjutnya, jika skrip tidak mengandung perintah yang membaca stdin setelah readmaka baris yang belum dibaca dieksekusi pada terminal interaktif setelah skrip berakhir. Adakah yang berhasil menguji ini?
Socowi
4

Membangun berdasarkan jawaban christophjaeger, saya menambahkan -sagar input tidak bergema ke terminal dan -nsehingga tidak menunggu baris baru.

while read -r -t 0; do
    read -n 256 -r -s
done
Peter Sutton
sumber
Menggunakan -nadalah ide yang bagus, tetapi dua jawaban sebelumnya telah menyebutkannya. Dan mengingat bahwa inti dari latihan ini adalah membaca dan membuang apa pun yang diketik sebelum read dieksekusi , saya tidak mengerti apa yang baik menurut Anda yang -sakan dilakukan.
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
Илья Антипов
sumber