it-swarm.com.de

Letzte Zeile am Terminal überschreiben

Mein Bash-Skript sieht folgendermaßen aus:

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

Es wird in die desc-Variable geschrieben, bis eine leere Zeile übergeben wird. Danach möchte ich andere Sachen lesen.

Wenn Sie mein aktuelles Skript ausführen, sieht es so aus:

Description:
Line 1
Line 2

Maintainer:

Ich möchte die letzte leere Zeile mit "Maintainer:" überschreiben.

Ich habe nach einer Lösung gesucht, aber nur Vorschläge gefunden, die mir gefallen haben

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

das bleibt in der Zeile und überschreibt es. Dies ist in meinem Fall nicht möglich.

42
Zulakis

Verwenden Sie einfach "\e[1A".

In Ihrem Beispiel löschen Sie den Text in derselben Zeile:

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

Wenn Sie zur vorherigen Zeile zurückkehren möchten, verwenden Sie\e [1A:

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

Wenn Sie in N Reihen gehen möchten, verwenden Sie \e[<N>A.

64
Igor Chubin

Ich baute eine Funktion von Dennis Williamsons Kommentar :

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

Danke an Dennis Williamson

11
Murmel

Fand ein tolles Leitfaden zu Escape-Sequenzen und wollte einige Diskussionen hier erweitern. 

Wenn Sie auf ein Terminal schreiben, bewegen Sie einen unsichtbaren Cursor, ähnlich wie beim Schreiben in einen Texteditor. Bei Verwendung von echo wird die Ausgabe automatisch mit einem neuen Zeilenzeichen beendet, das den Cursor in die nächste Zeile bewegt.

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

Sie können -n verwenden, um die neue Zeile zu verhindern. Wenn Sie danach erneut ein Echo ausführen, wird sie an das Ende dieser Zeile angehängt

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

Der Cursor bleibt dort, wo er war, also können wir -n nicht zum Überschreiben der vorherigen Zeile verwenden, sondern müssen den Cursor nach links bewegen. Um dies zu tun, müssen wir ihm eine Escape-Sequenz geben, von der wir wissen, dass echo wir mit -e verwenden werden, und dann den Cursor bewegen, indem ein Rücklaufwagen \r bereitgestellt wird, der den Cursor an den Anfang der Zeile setzt.

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

Das sieht so aus, als hätte es funktioniert, aber sehen Sie, was passiert

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

Sehen Sie die zusätzlichen Zeichen? Wenn Sie einfach über die Zeile schreiben, werden nur die Zeichen geändert, an denen wir sie geschrieben haben. 

Um das Problem zu beheben, verwendet die oben genannte Antwort das Escape-Zeichen \e[0K, um alles nach dem Cursor zu löschen, nachdem sich der Cursor nach links bewegt hat. d. h. \r zum Anfang gehen \e[0K löschen zum Ende.

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

Important\e zum Starten von Escape-Sequenzen funktioniert in zsh, jedoch nicht in sh und nicht unbedingt in bash, jedoch funktioniert \033 in allen. Wenn Sie möchten, dass Ihr Skript überall funktioniert, sollten Sie \033 bevorzugen.

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

Escape-Zeichen können jedoch noch mehr Nutzen bringen. Zum Beispiel bewegt \033[1A den Cursor in die vorherige Zeile, so dass wir den -n nicht für das vorherige Echo benötigen:

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

\r zum Anfang bewegen \033[1A nach oben \033[0K löschen bis zum Ende

Schließlich ist das alles in meinem Buch etwas chaotisch, also kannst du daraus eine Funktion machen:

overwrite() { echo -e "\r\033[1A\033[[email protected]"; }

Bei Verwendung von [email protected] werden einfach alle Parameter der Funktion in den String eingefügt

$ echo Longer sentance && overwrite Short sentence
Short sentence

Ich hoffe, das hilft Leuten, die mehr wissen wollen.

8
DanielM

Wenn Sie ohne das Zeilenvorschubzeichen echo -n "Something" ein Echo ausführen, können Sie \r mit dem nächsten Echo verwenden, um den 'Cursor' an den Anfang der Zeile echo -e "\\rOverwrite something" zu verschieben.

 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"

Beachten Sie nur, dass, wenn Ihre neue Zeichenfolge kürzer als Ihre alte Zeichenfolge ist, das Ende Ihrer alten Zeichenfolge weiterhin sichtbar ist. Beachten Sie den done.. im obigen Gif.

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

Diese Lösung vermeidet die leere Zeile, aber die Eingabe wird nicht wiederholt, bevor die Zeilen abgeschlossen sind.

Hinweis: Meine Version von bash hat "[$ finishInput -eq 0]" nicht akzeptiert.

1
Michael Besteck

Wenn Sie ein Skript in einer Schleife ausführen möchten, ohne den Scrollback zu sprengen, können Sie das folgende Muster verwenden:

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

Ersetzen Sie einfach den Befehl script durch Ihren eigenen.

0
maxywb