Je veux implémenter une barre de progression affichant les secondes écoulées dans bash. Pour cela, j'ai besoin d'effacer la dernière ligne affichée à l'écran (la commande "clear" efface tout l'écran, mais je dois effacer uniquement la ligne de la barre de progression et la remplacer par les nouvelles informations).
Le résultat final devrait ressembler à:
$ Elapsed time 5 seconds
Ensuite, après 10 secondes, je veux remplacer cette phrase (dans la même position à l'écran) par:
$ Elapsed time 15 seconds
faire écho à un retour chariot avec\r
seq 1 1000000 | while read i; do echo -en "\r$i"; done
de l'écho de l'homme:
-n do not output the trailing newline
-e enable interpretation of backslash escapes
\r carriage return
Le retour chariot seul ne déplace le curseur qu'au début de la ligne. C'est OK si chaque nouvelle ligne de sortie est au moins aussi longue que la précédente, mais si la nouvelle ligne est plus courte, la ligne précédente ne sera pas complètement écrasée, par exemple:
$ echo -e "abcdefghijklmnopqrstuvwxyz\r0123456789"
0123456789klmnopqrstuvwxyz
Pour réellement effacer la ligne du nouveau texte, vous pouvez ajouter \033[K
après le \r
:
$ echo -e "abcdefghijklmnopqrstuvwxyz\r\033[K0123456789"
0123456789
La réponse de Derek Veit fonctionne bien tant que la longueur de ligne ne dépasse jamais la largeur du terminal. Si ce n'est pas le cas, le code suivant empêchera la sortie indésirable:
avant que la ligne ne soit écrite pour la première fois, faites
tput sc
qui enregistre la position actuelle du curseur. Maintenant, chaque fois que vous souhaitez imprimer votre ligne, utilisez
tput rc
tput ed
echo "your stuff here"
pour revenir d'abord à la position de curseur enregistrée, puis effacer l'écran du curseur vers le bas et enfin écrire la sortie.
La méthode\033 n'a pas fonctionné pour moi. La méthode\r fonctionne mais elle n'efface rien, place simplement le curseur au début de la ligne. Donc, si la nouvelle chaîne est plus courte que l'ancienne, vous pouvez voir le texte restant à la fin de la ligne. Au final, tput était la meilleure solution. Il a d'autres utilisations en plus du curseur et il est préinstallé dans de nombreuses distributions Linux et BSD, il devrait donc être disponible pour la plupart des utilisateurs de 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
Voici un petit script de compte à rebours pour jouer avec:
#!/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"
Dans le cas où la sortie de progression est multi-lignes, ou si le script aurait déjà imprimé le nouveau caractère de ligne, vous pouvez sauter les lignes avec quelque chose comme:
printf "\033[5A"
ce qui fera sauter le curseur de 5 lignes vers le haut. Ensuite, vous pouvez remplacer tout ce dont vous avez besoin.
Si cela ne fonctionnait pas, vous pourriez essayer printf "\e[5A"
ou echo -e "\033[5A"
, qui devrait avoir le même effet.
Fondamentalement, avec séquences d'échappement vous pouvez contrôler presque tout sur l'écran.
Utilisez le caractère de retour chariot:
echo -e "Foo\rBar" # Will print "Bar"
Peut y parvenir en plaçant le retour chariot \r
.
Dans une seule ligne de code avec printf
for i in {10..1}; do printf "Counting down: $i\r" && sleep 1; done
ou avec echo -ne
for i in {10..1}; do echo -ne "Counting down: $i\r" && sleep 1; done