Questão Substituir a saída anterior no Bash em vez de anexá-la


Para um temporizador bash eu uso este código:

#!/bin/bash
sek=60
echo "60 Seconds Wait!"
echo -n "One Moment please "
while [ $sek -ge 1 ]
do
   echo -n "$sek "  
sleep 1
   sek=$[$sek-1]
done
echo
echo "ready!"

Isso me dá algo parecido

One Moment please: 60 59 58 57 56 55 ...

Existe a possibilidade de substituir o último valor de segundo pelo mais recente, de modo que a saída não gere uma trilha grande, mas a contagem regressiva de segundos, como um tempo real em uma posição? (Espero que você entenda o que eu quero dizer :))


17
2017-12-04 11:43


origem


Pode haver uma maneira de fazer isso com o watch comando, embora eu não tenho certeza exatamente como fazê-lo. - AJMansfield


Respostas:


#!/bin/bash
sek=60
echo "60 Seconds Wait!"
echo -n "One Moment please "
while [ $sek -ge 1 ]
do
   echo -n "$sek" 

sleep 1
   sek=$[$sek-1]
   echo -en "\b\b"
done
echo
echo "ready!"

14
2017-12-04 11:55



Incrível, muito obrigado. Apenas um aviso para os outros leitores. Para ajustar o código acima, você tem que usar echo -en "\ b \ b \ b" por causa do espaço. - NES
+ 1 bom, mas ... abaixo de 10 começa a comer a mensagem ... - lepe
Sim, melhor usar \r. Veja minha resposta. - Mikel
Do manual do bash: The old format $[expression] is deprecated and will be removed in upcoming versions of bash.. Use o POSIX $((expression)) ou o ((comando em vez disso. Por exemplo. sek=$(( sek - 1 )) ou (( sek = sek - 1 )) ou (( sek-- )). - geirha


Basicamente o mesmo que a resposta de aneeshep, mas usa Return (\r) em vez de retroceder (\b) porque não sabemos se o comprimento será sempre o mesmo, por ex. quando $sek < 10.

Além disso, o seu primeiro echo Deveria usar $seknão código rígido 60.

Finalmente, observe o espaço após o ....

#!/bin/bash
sek=60
echo "$sek Seconds Wait!"
while [ $sek -ge 1 ]
do
   echo -ne "One Moment please $sek ... \r"
   sleep 1
   sek=$[$sek-1]
done
echo
echo "ready!"

16
2018-02-03 23:44





Com o bash você pode usar a variável especial SECONDS.

#BASH
SECONDS=0;
while sleep .5 && ((SECONDS <= 60)); do 
    printf '\r%s: %2d' "One moment please" "$((60-SECONDS))"
done
printf '\n'

7
2018-02-03 23:18



+ 1 boa resposta, mais eu nunca soube sobre SECONDS. - Mikel
Funciona, mas é um pouco estranho ver 'sleep .5' como uma condição de loop while testada. Howerver Gosto particularmente do uso de $ SECONDS, porque se relaciona com o tempo real (ou seja, não é um tempo fixo decorrido entre ações demoradas, como no sono 1) ... SECONDS  Essa variável se expande para o número de segundos desde que o shell foi iniciado.(então eu provavelmente não configuraria para 0 .. apenas teste por 60 segundos a mais de quando o script começou) .. +1 - Peter.O
Eu estou comentando mais, só porque eu estou pessoalmente interessado em uma maneira de obter um coutntdown preciso ... Eu testei $ SECONDS e parece que se ele está definido para '0' ou não, ainda é dependente do segundo fracional atual do sistema. Configurar para '0' pode resultar em um tempo de 0,99 ... (o mesmo vale se for deixado como está) .... Então, sua melhor chance média é estar dentro de apenas 0,5 de segundo. .. Apenas um comentário (é isso que os comentários são para :) - Peter.O
@ fred.bear Bem, você nunca vai realmente acertar; algum outro processo poderia começar a sobrecarregar a CPU e / ou IO enquanto a contagem regressiva está indo e arruinar qualquer precisão que você tivesse anteriormente. O que você pode fazer é esperar que finalmente X quantidade de tempo, e dar uma contagem regressiva, se desejar. Quando um programa diz "vai demorar um minuto", você espera que ele demore exatamente 1 minuto, até o milissegundo? ou levar 1 minuto, mais ou menos alguns segundos? - geirha
@geirha ... Sim, essa variação não importará em 99% dos casos, e é ótimo que você tenha me dado conhecimento de $ SECONDS ... Estou apenas encontrando seus limites ... Eu toquei com um Variação do seu script que relata o tempo de término com base em um sono de 0,01 segundo (mais, como você mencionou, qualquer atraso do sistema externo), mas só imprimindo quando um segundo clica, mas descobri que o primeiro 'segundo' estava imprimindo muito cedo (em um caso, logo após o primeiro. 01 seg) .. É tudo parte da minha curva de aprendizado bash ... Eu gosto da sua resposta, é por isso que eu tive uma visão mais profunda. - Peter.O


Isto é o que eu fiz depois de ler aqui e um pouco mais, o único forro:

SEC=101;for i in `seq $SEC -1 1`;do printf "\rNext in: %`expr length $SEC`ds" "$i";sleep 1;done;echo

Mais legível:

#!/bin/bash
SEC=101

for i in `seq $SEC -1 1`;do
        printf "\rNext in: %`expr length $SEC`ds" "$i";
        sleep 1;
done
echo

Onde SEC pode ser definido para qualquer número inteiro positivo e o printf vai cuidar de preenchimento apropriado. Testado no Ubuntu e no cygwin.


1
2017-11-23 21:22





Além de \r ou \b abordagens, é possível usar o \033[2K  personagem de controle, que diz ao terminal para limpar toda a linha. A vantagem disso em comparação com \b é que você não precisa corresponder ao número de \b com a quantidade de caracteres que você deseja excluir e comparado a \r não haverá caracteres aparecendo na tela se a nova linha for menor que a antiga.

Abaixo está o exemplo de como ele pode ser aplicado a essa pergunta e Aqui é um exemplo do aplicativo relacionado para criar saída semelhante a mensagens de inicialização. Neste exemplo em particular, o temporizador desaparecerá quando o 0o segundo for atingido e a linha do temporizador será substituída por "Pronto!" frase.

#!/bin/bash
sek=60
echo "60 Seconds"

while ((sek--)); do
    printf "One moment please: %d" "$sek"
    sleep 1
    printf "\r%b" "\033[2K"
done
echo "Ready!"

Outra alternativa seria empregar dialog comando para criar diálogos simples na linha de comando. A caixa de diálogo permanecerá na tela durante a duração do cronômetro e será atualizada com o loop, e pelo tempo que for feito - o cronômetro será substituído pela mensagem "Pronto! Pressione para sair" de uma maneira perfeita:

#!/bin/bash
sek=60
echo "60 Seconds"

while ((sek--)); do
    echo "$sek" | dialog --progressbox "Please wait" 10 25
    sleep 1
done
dialog --msgbox "Ready! Press <OK> to finish" 10 25

1
2018-06-18 01:05





Temporizador de contagem regressiva:

MIN=1 && for i in $(seq $(($MIN*60)) -1 1); do echo -n "$i, "; sleep 1; done; echo -e "nnMessage"

e o cronômetro 'normal' é:

START=$( date +%s ); while true; do CURRENT=$( date +%s ) ; echo $(( CURRENT-START )) ; sleep 1 ; echo -n  ; done

controle + c para parar


-2
2017-12-04 13:20



Isso não responde à pergunta sobre sobrescrever texto - Jeremy Kerr