Wie ändere ich den Inhalt einer Zeile im Terminal, anstatt eine neue zu schreiben?

24

Wenn also wgeteine Webseite aufgerufen wird, wird eine Statusleiste angezeigt, die angibt, wie viel die Datei (en) heruntergeladen wurden. Es sieht aus wie das:

25%[=============>______________________________________] 25,000 100.0K/s (Unterstriche sind Leerzeichen. Ich konnte nur nicht herausfinden, wie ich mehr als ein Leerzeichen hintereinander einfügen kann.)

Anstatt jedoch eine weitere Zeile in stdout zu schreiben und eine weitere Fortschrittsanzeige hinzuzufügen, wird diese folgendermaßen aktualisiert:

50%[===========================>________________________] 50,000 100.0K/s

Und das wgetist auch nicht das einzige Beispiel. Wenn Sie beispielsweise etwas einleiten lessund dann beenden, ist Ihre ursprüngliche Eingabeaufforderung immer noch vorhanden, zusammen mit dem Ergebnis der zuvor ausgeführten Befehle. Es ist, als wärst du nie gegangen.

Meine Fragen sind also, wie heißt das, wie implementiere ich es, funktioniert es jeweils nur für eine einzelne Zeile, und kann ich das in C verwenden?

vier
quelle
5
Ich empfehle BashFAQ 44 zu lesen . Vielleicht findest du es interessant.
JW013

Antworten:

32

Zuallererst hat Ihre Frage nichts mit Bash zu tun, sondern mit dem Terminal. Das Terminal antwortet auf die Anzeige des Textes der Programme und die Bash selbst hat nach dem Start keine Kontrolle über die Programme.

Terminals bieten Steuersequenzen zur Steuerung von Farbe, Schriftart, Cursorposition und mehr. Eine Liste der standardisierten Terminalsequenzen finden Sie beispielsweise unter http://www.termsys.demon.co.uk/vtansi.htm

  • positionieren Sie den Cursor an den Zeilenanfang
  • lösche die Zeile danach
  • schreibe eine neue Zeile

um einen Fortschrittsbalken zu erstellen.

Fortgeschrittenere Terminal-Escape-Sequenzen sind typischerweise terminalabhängig, zB arbeiten sie nur mit Eterm oder xterm. ncurses - ist eine Programmierbibliothek, mit der Sie interaktive Programme mit dem Terminal erstellen können, sodass Sie keine Escape-Sequenzen verwenden müssen.

So überschreiben Sie eine vorhandene Zeile mit terminalen Sequenzen

echo long text
sleep 1
printf "\033[1A"  # move cursor one line up
printf "\033[K"   # delete till end of line
echo foo

So überschreiben Sie eine bestehende Zeile ohne Klemmenfolge

Eine einfache Lösung besteht darin, am Ende keine neue Zeile, sondern einen Wagenrücklauf zu schreiben, der den Cursor im Grunde genommen an den Zeilenanfang zurücksetzt, z.

echo -n first 
sleep 1 
echo -ne "\rsecond"
echo

Der \rZeilenumbruch oder der Zeilenumbruch setzen den Cursor an den Anfang der Zeile und ermöglichen es Ihnen, den Inhalt der Zeile zu überschreiben.

Zwischen Puffern wie lessoder wechselnvi

Das Verhalten von lessist auch auf eine erweiterte Terminalfunktion zurückzuführen, den alternativen Bildschirm:

Im VT102-Modus gibt es Escape-Sequenzen zum Aktivieren und Deaktivieren eines alternativen Bildschirmpuffers, der dieselbe Größe wie der Anzeigebereich des Fensters hat. Bei Aktivierung wird der aktuelle Bildschirm gespeichert und durch den alternativen Bildschirm ersetzt. Das Speichern von Zeilen, die vom oberen Rand des Fensters gescrollt wurden, ist deaktiviert, bis der normale Bildschirm wiederhergestellt ist. Der Eintrag termcap (5) für xterm ermöglicht es dem visuellen Editor vi (1), zum Bearbeiten zum alternativen Bildschirm zu wechseln und den Bildschirm beim Beenden wiederherzustellen. Ein Popup-Menüeintrag erleichtert das Umschalten zwischen dem normalen und dem alternativen Bildschirm zum Ausschneiden und Einfügen.

http://rosettacode.org/wiki/Terminal_control/Preserve_screen listet einige Beispiele auf, wie Sie dies selbst tun können, entweder über tput oder über einige Escape-Sequenzen.

Ulrich Dangel
quelle
15

Verwenden Sie - echo, anstatt automatisch eine neue Zeile an den String anzuhängen. printf "%s\r" whateverDer Wagenrücklauf setzt den Cursor an den Anfang der aktuellen Zeile. Beispiel:

seq 1 15 | while read num; do printf "%2d\r" $num; sleep 1; done; echo ""
Glenn Jackman
quelle
Je nach Cursor Ihres Terminals ist dies möglicherweise angenehmerprintf "\r%2d " $num
Glenn Jackman