Sovrascrivi l'output precedente in Bash invece di aggiungerlo


22

Per un timer bash uso questo codice:

#!/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!"

Questo mi dà qualcosa del genere

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

Esiste la possibilità di sostituire l'ultimo valore del secondo con il più recente in modo che l'uscita non generi una scia di grandi dimensioni ma il conto alla rovescia dei secondi come un tempo reale in una posizione? (Spero tu capisca cosa intendo :))


Potrebbe esserci un modo per farlo con il watchcomando, anche se non sono sicuro di come farlo.
AJMansfield,

Risposte:


14
#!/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!"

2
Fantastico, grazie mille. Solo un avviso per gli altri lettori. Per adattare il codice sopra devi usare echo -en "\ b \ b \ b" a causa dello spazio.
NES,

1
+1 Bello, ma ... sotto i 10 inizia a mangiare il messaggio ...
lepe

1
Sì, meglio usare \r. Vedi la mia risposta
Mikel,

3
Da manuale di bash: The old format $[expression] is deprecated and will be removed in upcoming versions of bash.. Utilizzare invece POSIX $((expression))o il ((comando-. Ad esempio sek=$(( sek - 1 ))o (( sek = sek - 1 ))o (( sek-- )).
geirha,

17

Sostanzialmente uguale alla risposta di aneeshep, ma utilizza Return ( \r) anziché Backspace ( \b) perché non sappiamo se la lunghezza sarà sempre la stessa, ad esempio quando $sek < 10.

Inoltre, il primo echodovrebbe usare $sek, non hard-code 60.

Infine, nota lo spazio dopo il ....

#!/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!"

7

Con bash puoi usare la variabile speciale SECONDS.

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

+1 Buona risposta, in più non ho mai saputo di SECONDS.
Mikel,

Funziona, ma è un po 'strano vedere' sleep .5 'come una condizione di ciclo continuo testata. Howerver Mi piace particolarmente l'uso di $ SECONDS, perché si riferisce al tempo reale, (cioè non un tempo trascorso fisso tra azioni dispendiose in termini di tempo, come nel caso del sonno 1) ... SECONDS Questa variabile si espande al numero di secondi dall'avvio della shell. (quindi probabilmente non lo imposterei su 0 .. testarlo per altri 60 secondi da quando è iniziato lo script) .. +1
Peter.O

Sto commentando ulteriormente, solo perché sono personalmente interessato a un modo per ottenere un coutntdown accurato ... Ho testato $ SECONDS e sembra che se è impostato su "0" o meno dipende ancora dal secondo frazionario attuale del sistema .. ie. Impostarlo su '0' può comportare un tempo di 0,99 ... (lo stesso vale se viene lasciato così com'è) .... Quindi, la sua migliore possibilità media è di essere entro 0,5 di secondo. .. Solo un commento (ecco a cosa servono i commenti :)
Peter.O

@ fred.bear Beh, non lo otterrai mai con precisione; qualche altro processo potrebbe iniziare a eseguire il hogging della CPU e / o IO mentre il conto alla rovescia procede e rovinare la precisione che avevi in ​​precedenza. Quello che puoi fare è farlo aspettare almeno X quantità di tempo e dare un conto alla rovescia se lo desideri. Quando un programma dice "ci vorrà un minuto", ti aspetti che impieghi esattamente 1 minuto, al millisecondo? o prendere 1 minuto, dare o prendere qualche secondo?
geirha,

@geirha ... Sì, quella variazione non avrà importanza nel 99% dei casi, ed è bello che tu mi abbia fatto conoscere $ SECONDS ... Sto solo trovando i suoi limiti ... Ho giocato con un variazione del tuo script che riporta il tempo di finitura in base a una sospensione di 0,01 secondi (più, come hai detto, qualsiasi ritardo del sistema esterno) ma stampa solo quando un secondo fa clic, ma poi ho scoperto che il primo "secondo" stava stampando troppo presto (in un caso, subito dopo i primi 0,01 secondi) .. Fa tutto parte della mia curva di apprendimento bash ... Mi piace la tua risposta, ecco perché l'ho vista più da vicino.
Peter

3

Oltre a \ro \bapprocci, è possibile utilizzare il \033[2K carattere di controllo , che indica al terminale di cancellare l'intera linea. Il vantaggio di questo rispetto \bè che non è necessario abbinare il numero di \bcon la quantità di caratteri che si desidera eliminare, e rispetto a \rnon ci saranno caratteri che sporgono sullo schermo se la nuova linea è più corta della vecchia uno.

Di seguito è riportato l'esempio di come può essere applicato a questa domanda, ed ecco un esempio dell'applicazione correlata per creare output simile ai messaggi di avvio. In questo esempio particolare, il timer sparirà una volta raggiunto lo 0 ° secondo e la linea del timer verrà sostituita con "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!"

Un'altra alternativa sarebbe quella di utilizzare il dialogcomando per creare semplici finestre di dialogo nella riga di comando. La finestra di dialogo rimarrà sullo schermo per tutta la durata del timer e si aggiornerà con il loop e, una volta terminato, il timer verrà sostituito con il messaggio "Pronto! Premere per uscire" in modo continuo:

#!/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

dialognon esiste su mac: /
Ricky Levi il

1

Questo è quello che mi è venuto in mente dopo aver letto qui e un po 'di più, l'unica riga:

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

Più leggibile:

#!/bin/bash
SEC=101

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

Dove SEC può essere impostato su qualunque numero intero positivo e printf si occuperà dell'imbottitura appropriata. Testato sotto Ubuntu e Cygwin.


1

Può raggiungerlo posizionando il ritorno a capo \r.

In una singola riga di codice, è possibile con echo -ne

for i in {60..1}; do echo -ne "One moment please: $i\r" && sleep 1; done

o con printf

for i in {60..1}; do printf "One moment please: $i\r" && sleep 1; done

-2

Conto alla rovescia:

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

e il cronometro "normale" è:

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

control + c per fermare


Questo non risponde alla domanda sulla sovrascrittura del testo
Jeremy Kerr,
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.