web-dev-qa-db-fra.com

Ecraser la dernière ligne du terminal

Mon script bash se présente comme suit:

echo "Description:"
while [ $finishInput -eq 0 ]; do
read tmp
desc="$desc"$'\n'"$tmp"
if [ -z "$tmp" ]; then
finishInput="1"
fi
done
echo -n "Maintainer:"
read maintainer

Il lit dans la variable jusqu'à ce qu'une ligne vide soit passée. Après cela, je veux lire d'autres choses.

Lors de l'exécution de mon script actuel, il ressemble à ceci:

Description:
Line 1
Line 2

Maintainer:

Je voudrais écraser la dernière ligne vide avec "Maintainer:".

J'ai cherché une solution mais n'ai trouvé que des suggestions qui ressemblaient à

echo -n "Old line"
echo -e "\r new line"

qui reste sur la ligne et l’écrase. Ce n'est pas possible dans mon cas.

42
Zulakis

Il suffit d'utiliser "\e[1A".

Dans votre exemple, vous supprimez le texte sur la même ligne:

$ echo -n "Old line"; echo -e "\e[0K\r new line"
 new line

Pour revenir à la ligne précédente, utilisez\e [1A:

$ echo "Old line"; echo -en "\e[1A"; echo -e "\e[0K\r new line"
 new line

Si vous voulez utiliser N lignes, utilisez \e[<N>A.

64
Igor Chubin

J'ai construit une fonction de Dennis Williamsons Commentaire :

function clearLastLine() {
        tput cuu 1 && tput el
}

Merci à Dennis Williamson

11
Murmel

J'ai trouvé un bon guide sur les séquences d'échappement et je souhaite développer certaines des discussions ici 

Lorsque vous écrivez sur un terminal, vous déplacez un curseur invisible, comme lorsque vous écrivez dans n’importe quel éditeur de texte. Lorsque vous utilisez echo, la sortie se termine automatiquement par un nouveau caractère de ligne déplaçant le curseur à la ligne suivante.

$ echo "Hello" && echo " World"
Hello
 World

Vous pouvez utiliser -n pour empêcher la nouvelle ligne et si vous répétez l’écho après cela, il sera ajouté à la fin de cette ligne.

$ echo -n "Hello" && echo " World"
Hello World

Le curseur reste là où il était, donc seul, nous ne pouvons pas utiliser -n pour écraser la ligne précédente, nous devons déplacer le curseur à gauche. Pour ce faire, nous devons lui donner une séquence d'échappement, que nous avons laissée à echo savoir que nous allons utiliser avec -e, puis déplacer le curseur en fournissant un retour chariot \r qui le place au début de la ligne.

$ echo -n "Hello" && echo -e "\rWorld"
World

Cela peut sembler fonctionner, mais voyez ce qui se passe avec

$ echo -n "A longer sentance" && echo -e "\rShort sentance"
Short sentancence

Voir les caractères supplémentaires? Écrire simplement par-dessus la ligne ne change que les caractères où nous les avons écrits. 

Pour résoudre ce problème, la réponse acceptée ci-dessus utilise le caractère d'échappement \e[0K pour tout effacer après le curseur, après le déplacement du curseur vers la gauche. c.-à-d. \r aller au début \e[0K effacer pour finir.

$ echo -n "A longer sentance" && echo -e "\r\e[0KShort sentance"
Short sentance

Important\e pour commencer les séquences d'échappement fonctionne dans zsh mais pas dans sh et pas nécessairement dans bash, cependant \033 fonctionne dans chacune d'elles. Si vous voulez que votre script fonctionne n'importe où, vous devriez préférer \033

$ echo -n "A longer sentance" && echo -e "\r\033[0KShort sentance"
Short sentance

Mais les caractères d'échappement peuvent fournir encore plus d'utilité. Par exemple, \033[1A déplace le curseur sur la ligne précédente, nous n'avons donc pas besoin du -n sur l'écho précédent:

$ echo "A longer sentance" && echo -e "\r\033[1A\033[0KShort sentance"
Short sentance

\r déplacer au début \033[1A déplacer vers le haut \033[0K effacer jusqu'à la fin

Enfin, tout cela est un peu brouillon dans mon livre, vous pouvez donc le transformer en une fonction:

overwrite() { echo -e "\r\033[1A\033[0K$@"; }

Utiliser $@ place simplement tous les paramètres de la fonction dans la chaîne

$ echo Longer sentance && overwrite Short sentence
Short sentence

J'espère que cela aidera les gens qui veulent en savoir un peu plus.

8
DanielM

Si vous effectuez un écho sans le caractère de nouvelle ligne echo -n "Something", vous pouvez utiliser \r avec votre prochain écho pour déplacer le 'curseur' au début de la ligne echo -e "\\rOverwrite something".

 bash overwrite terminal line

#!/bin/bash

CHECK_MARK="\033[0;32m\xE2\x9C\x94\033[0m"

echo -e "\n\e[4mDoing Things\e[0m"
echo -n "doing thing 1..."
sleep 1
echo -e "\\r${CHECK_MARK} thing 1 done"

Sachez simplement que si votre nouvelle chaîne est plus courte que votre ancienne chaîne, la queue de votre ancienne chaîne sera toujours visible. Notez le done.. dans le gif ci-dessus.

5
Derek Soike
#!/bin/bash

echo "Description:"
while test -z $finishInput; do
 read -s tmp
 desc="$desc"$'\n'"$tmp"
 if [ -z "$tmp" ]; then
 finishInput=1
 else
    echo $tmp
 fi
 #echo "fi="$finishInput;
done
echo -n "Maintainer:"
read maintainer

Cette solution évite les lignes vides, mais les entrées ne sont pas répercutées avant la fin des lignes.

Astuce: ma version de bash n'accepte pas "[$ finishInput -eq 0]".

1
Michael Besteck

Si vous voulez exécuter un script en boucle sans exploser votre défilement, vous pouvez utiliser le modèle suivant:

while sleep 10s; do 
  echo -n $(script)
  echo -n -e "\e[0K\r"
done

Il suffit de remplacer la commande script par la vôtre.

0
maxywb