Wyczyść standardowe wejście przed czytaniem

14

Mam następujący skrypt bash:

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

Teraz, jak można się domyślać, jeśli użytkownik naciśnie jakieś losowe klawisze podczas „czasochłonnego zadania”, niechciane dane są również brane pod uwagę. Jak wyczyścić stdin(a przynajmniej zignorować) przed wydaniem polecenia odczytu?

rabin
źródło
1
Ja, chyba że piszesz program podobny do przekleństw, znajduję to, co chcesz zrobić, aby być wadą projektową w twoim programie. UNIX / Linux ma bardzo przydatną funkcję buforowania danych wejściowych („typowanie z wyprzedzeniem”) i zwykle korzystam z tej funkcji. Przechodząc przez twój program, gdzie wyrzucasz to, co wpisałem, prawdopodobnie zgłosiłbym błąd i przestałbym używać twojego programu, dopóki nie zostanie naprawiony.
Arcege
1
Niektórzy użytkownicy mają irytujący zwyczaj gry na pianinie przy użyciu klawiatury, gdy ich program jest zajęty robieniem czegoś. Wolę wyrzucić te naciśnięcia klawiszy i zacząć od nowa. Ale masz rację, „typowanie z wyprzedzeniem” jest przydatne, ale nie zawsze.
rabin

Odpowiedzi:

8

Nie sądzę, że istnieje sposób na wyczyszczenie standardowego wejścia, ale (za pomocą bash) możesz przeczytać i odrzucić to, co tam jest, zanim poprosisz o dane wejściowe

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

Odczytuje to stdin i ma limit czasu 1 sekundy, ale kończy się niepowodzeniem, jeśli w stdin jest więcej niż 10000 znaków. Nie wiem, jak duży możesz zrobić parametr nchars.


źródło
Naprawdę znalazłem ten hack na forum. Spodziewałem się znaleźć lepszy sposób na zrobienie tego. Najwyraźniej nie.
rabin
@rabin: Jeśli znajdziesz lepszy sposób na opublikowanie tutaj, mam go w kilku skryptach.
Niestety nie działa to ze wszystkimi powłokami, np. Dash :(
scai
21

W Bash 4 możesz ustawić -t(limit czasu) na 0. W takim przypadku readnatychmiast wraca ze statusem wyjścia wskazującym, czy dane czekają, czy nie:

# do some time consuming task here
while read -r -t 0; do read -r; done
read -p "Give me some input: " input
Christophjaeger
źródło
Wydaje się, że działa to tylko wtedy, gdy użytkownik nacisnął klawisz Enter po klawiszach. Jeśli użytkownik właśnie wpisał losowe klawisze (i nie ma wciśnięcia Enter), pętla kończy się natychmiast bez usuwania buforowanych znaków.
BT
6
read -d '' -t 0.1 -n 10000

Odczytuje to wiele wierszy danych wejściowych, jeśli użytkownik przypadkowo naciśnie przycisk, aby wejść wielokrotnie

Ram Natarajan
źródło
5

to działało dla mnie dobrze:

function clean_stdin()
{
    while read -e -t 0.1; do : ; done
}
pschichtel
źródło
dlaczego -ew tym przypadku?
nhed
@nhed już nie jestem pewien, może w celu obejścia jakiegoś specyficznego problemu systemowego
pschichtel 19.04.17
4

Dołącz czasochłonne zadanie do bloku, którego standardowe wejście jest zamknięte:

{
     # time consuming task
} <&-

read -p "Give me some input: " input
artistoex
źródło
Uważam, że nie ma to nic wspólnego z pytaniem.
Scott,
Ale tak jest! Użytkownik chce, aby wszystkie dane wejściowe zostały odrzucone. Nie zezwalanie na wprowadzanie danych robi dokładnie to - ponieważ standardowe wejście jest zamknięte, wszystkie dane wejściowe są odrzucane (przez system). To eleganckie rozwiązanie jego problemu. Sprawia, że ​​system wykonuje odrzut bez kłopotów z napisaniem pętli odrzutów.
HiTechHiTouch
Jest to jak dotąd najbardziej niezawodna opcja.
Stephen Eilert
Wydaje się idealny, ale dla mnie nie działa. Próbowałem bash 5.0.0 i 4.4.19. readnadal będzie czytać pierwszą linię wprowadzoną podczas # time consumingzadania. Ponadto, jeśli skrypt nie zawiera żadnych poleceń, które czytają stdin po tym readczasie, nieprzeczytane linie są wykonywane na interaktywnym terminalu po zakończeniu skryptu. Czy ktoś pomyślnie to przetestował?
Socowi
4

Opierając się na odpowiedzi christophjaegera, dodałem -s, aby dane wejściowe nie były powtarzane na terminalu i -naby nie czekał na nową linię.

while read -r -t 0; do
    read -n 256 -r -s
done
Peter Sutton
źródło
Używanie -njest dobrym pomysłem, ale dwie poprzednie odpowiedzi już o tym wspominały. Biorąc pod uwagę, że celem tego ćwiczenia jest przeczytanie i odrzucenie czegokolwiek, co zostało wpisane przed read wykonaniem , nie rozumiem, co według ciebie będzie dobre -s.
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
Илья Антипов
źródło