Limpar stdin antes de ler


14

Eu tenho o seguinte script bash:

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

Agora, como você deve ter adivinhado, se um usuário pressionar algumas teclas aleatórias durante a "tarefa demorada", a entrada indesejada será levada em consideração também. Como limpo stdin(ou pelo menos o ignoro) antes de emitir o comando de leitura?


1
Eu mesmo, a menos que você esteja escrevendo um programa parecido com maldições, acho que o que você deseja fazer é uma falha de design em seu programa. O UNIX / Linux possui o recurso muito útil de entrada em buffer ("digitação antecipada") e eu geralmente uso essa funcionalidade. Encontrando seu programa em que você joga fora o que eu digitei, provavelmente enviaria um erro e pararia de usá-lo até que ele fosse corrigido.
Arcege

1
Alguns usuários têm o hábito irritante de tocar piano com o teclado enquanto o programa está ocupado fazendo alguma coisa. Prefiro jogar fora essas teclas e começar de novo. Mas você está certo, a "digitação antecipada" é útil, mas nem sempre.
rabin

Respostas:


8

Eu não acho que exista uma maneira de limpar o stdin, mas (com o bash) você pode ler e descartar o que há antes de solicitar a entrada

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

Ele lê stdin e tem um tempo limite de 1 segundo, mas falha se houver mais de 10000 caracteres no stdin. Não sei quão grande você pode criar o parâmetro nchars.


Na verdade, eu encontrei esse hack em um fórum. Eu esperava encontrar uma maneira melhor de fazê-lo. Aparentemente não.
rabin

@rabin: Se você encontrar uma maneira melhor de postar aqui, eu a tenho em alguns scripts.

Infelizmente, isso não funciona com todas as conchas, por exemplo, dash :(
scai

20

No Bash 4, você pode definir -t(tempo limite) para 0. Nesse caso, readretorna imediatamente com um status de saída indicando se há dados aguardando ou não:

# 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

Isso lê várias linhas de entradas, se o usuário pressionar inadvertidamente a tecla Enter várias vezes.


5

Isto funcionou bem para mim:

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

por que -eneste caso?
nhed

@nhed não sei mais, talvez para contornar um problema específico do sistema
pschichtel

4

Coloque a tarefa demorada em um bloco cujo stdin está fechado:

{
     # time consuming task
} <&-

read -p "Give me some input: " input

Eu acredito que isso não tem nada a ver com a questão.
Scott

Mas faz! O usuário deseja que todas as entradas sejam descartadas. Não permitir a entrada faz exatamente isso - já que o stdin está fechado, toda a entrada é descartada (pelo sistema). É uma solução elegante para o problema dele. Ele faz com que o sistema faça o descarte sem o trabalho de gravar um loop de descarte.
HiTechHiTouch

Essa parece ser a opção mais confiável até agora.
Stephen Eilert

Parece perfeito, mas não funciona para mim. Eu tentei o bash 5.0.0 e 4.4.19. readainda lerá a primeira linha inserida durante a # time consumingtarefa. Além disso, se o script não contiver nenhum comando que leia stdin após o read, as linhas não lidas serão executadas no terminal interativo após o término do script. Alguém testou isso com sucesso?
Socowi 27/02/19

4

Com base na resposta do christophjaeger, acrescentei -spara que a entrada não ecoasse no terminal e -nnão esperasse por uma nova linha.

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

Usar -né uma boa ideia, mas duas respostas anteriores já a mencionaram. E, como o objetivo deste exercício é ler e descartar tudo o que foi digitado antes da read execução , não entendo o que você acha que -svai fazer.
51616 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
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.