Come eliminare e sostituire l’ultima riga nel terminale usando bash?

Voglio implementare una barra di avanzamento che mostra i secondi trascorsi in bash. Per questo, ho bisogno di cancellare l’ultima riga mostrata sullo schermo (il comando “cancella” cancella tutto lo schermo, ma ho bisogno di cancellare solo la riga della barra di avanzamento e sostituirla con le nuove informazioni).

Il risultato finale dovrebbe essere simile a:

$ Elapsed time 5 seconds 

Quindi dopo 10 secondi voglio sostituire questa frase (nella stessa posizione sullo schermo) da:

 $ Elapsed time 15 seconds 

echo un ritorno a capo con \ r

 seq 1 1000000 | while read i; do echo -en "\r$i"; done 

da uomo eco:

 -n do not output the trailing newline -e enable interpretation of backslash escapes \r carriage return 

Il carriage return da solo sposta il cursore all’inizio della riga. Va bene se ogni nuova linea di output è lunga almeno quanto quella precedente, ma se la nuova linea è più corta, la riga precedente non verrà completamente sovrascritta, ad esempio:

 $ echo -e "abcdefghijklmnopqrstuvwxyz\r0123456789" 0123456789klmnopqrstuvwxyz 

Per cancellare effettivamente la linea per il nuovo testo, puoi aggiungere \033[K dopo il \r :

 $ echo -e "abcdefghijklmnopqrstuvwxyz\r\033[K0123456789" 0123456789 

http://en.wikipedia.org/wiki/ANSI_escape_code

La risposta di Derek Veit funziona bene finché la lunghezza della linea non supera mai la larghezza del terminale. Se questo non è il caso, il codice seguente impedirà l’emissione di posta indesiderata:

prima che la riga sia scritta per la prima volta, fallo

 tput sc 

che salva la posizione corrente del cursore. Ora quando vuoi stampare la tua linea, usa

 tput rc tput ed echo "your stuff here" 

per prima cosa tornare alla posizione del cursore salvata, quindi cancellare lo schermo dal cursore alla fine e infine scrivere l’output.

Il metodo \ 033 non ha funzionato per me. Il metodo \ r funziona ma in realtà non cancella nulla, mette semplicemente il cursore all’inizio della riga. Quindi se la nuova stringa è più corta di quella vecchia puoi vedere il testo rimanente alla fine della riga. Alla fine, tput era il modo migliore per andare. Ha altri usi oltre a quello del cursore e viene fornito preinstallato in molte distribuzioni Linux e BSD, quindi dovrebbe essere disponibile per la maggior parte degli utenti bash.

 #/bin/bash tput sc # save cursor printf "Something that I made up for this string" sleep 1 tput rc;tput el # rc = restore cursor, el = erase to end of line printf "Another message for testing" sleep 1 tput rc;tput el printf "Yet another one" sleep 1 tput rc;tput el 

Ecco un piccolo script per il conto alla rovescia con cui giocare:

 #!/bin/bash timeout () { tput sc time=$1; while [ $time -ge 0 ]; do tput rc; tput el printf "$2" $time ((time--)) sleep 1 done tput rc; tput ed; } timeout 10 "Self-destructing in %s" 

Usa il carattere di ritorno a capo:

 echo -e "Foo\rBar" # Will print "Bar" 

Nel caso in cui l’output del progresso sia multi linea, o lo script avrebbe già stampato il carattere della nuova riga, puoi saltare le linee con qualcosa come:

printf "\033[5A"

che farà in modo che il cursore salti 5 linee in alto. Quindi puoi sovrascrivere quello che ti serve.

Se ciò non dovesse funzionare, potresti provare printf "\e[5A" o echo -e "\033[5A" , che dovrebbe avere lo stesso effetto.

Fondamentalmente, con le sequenze di escape puoi controllare quasi tutto sullo schermo.

Il modo più semplice è usare il carattere \r che immagino.

Lo svantaggio è che non è ansible avere linee complete, in quanto cancella solo la riga corrente.

Semplice esempio:

 time=5 echo -n "Elapsed $time seconds" sleep 10 time=15 echo -n "Elapsed $time seconds" echo "\nDone"