So überschreiben Sie eine vorhandene Zeile mit Terminalsequenzen

So überschreiben Sie eine vorhandene Zeile mit Terminalsequenzen

Wenn Sie also wgeteine Webseite aufrufen, wird Ihnen eine Statusleiste angezeigt, die angibt, wie viele Dateien heruntergeladen wurden. Sie sieht folgendermaßen aus:

25%[=============>______________________________________] 25,000 100.0K/s (Unterstriche sind Leerzeichen; ich konnte einfach nicht herausfinden, wie ich mehr als ein aufeinanderfolgendes Leerzeichen dort hineinbekomme)

Anstatt jedoch eine weitere Zeile in die Standardausgabe zu schreiben und einen weiteren Fortschrittsbalken hinzuzufügen, wird dieser folgendermaßen aktualisiert:

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

Und wgetdas ist nicht das einzige Beispiel dafür. Wenn Sie beispielsweise etwas per Pipe eingeben lessund dann beenden, ist Ihre ursprüngliche Eingabeaufforderung immer noch da, zusammen mit dem Ergebnis aller Befehle, die Sie zuvor ausgeführt haben. Es ist, als wären Sie nie weg gewesen.

Meine Fragen lauten also: Wie heißt das, wie implementiere ich es, funktioniert es immer nur für eine einzelne Zeile auf einmal und kann ich es in C verwenden?

Antwort1

Zunächst einmal hat Ihre Frage nichts mit Bash zu tun, sondern mit dem Terminal. Das Terminal ist für die Anzeige des Programmtexts zuständig, und Bash selbst hat nach dem Start keine Kontrolle mehr über die Programme.

Terminals bieten Steuersequenzen zur Steuerung von Farbe, Schriftart, Cursorposition und mehr. Eine Liste standardisierter Terminalsequenzen finden Sie unter http://www.termsys.demon.co.uk/vtansi.htmSie können beispielsweise

  • Positionieren Sie den Cursor am Anfang der Zeile
  • Löschen Sie die Zeile anschließend
  • eine neue Zeile schreiben

um einen Fortschrittsbalken zu erstellen.

Fortgeschrittenere Terminal-Escape-Sequenzen sind normalerweise terminalabhängig und funktionieren beispielsweise nur mit Eterm oder xterm.Abonnieren- ist eine Programmierbibliothek zum Erstellen interaktiver Programme mit dem Terminal, sodass Sie keine Escape-Sequenzen verwenden müssen.

So überschreiben Sie eine vorhandene Zeile mit Terminalsequenzen

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 vorhandene Zeile ohne Terminalsequenz

Eine einfache Lösung besteht darin, am Ende keinen Zeilenumbruch, sondern einen Wagenrücklauf zu schreiben, der den Cursor grundsätzlich an den Zeilenanfang zurücksetzt, zB:

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

Mit \roder der Wagenrücklauftaste wird der Cursor an den Zeilenanfang gesetzt und Sie haben die Möglichkeit, den Inhalt der Zeile zu überschreiben.

Wechseln Sie zwischen Puffern wie lessodervi

Das Verhalten 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. Wenn dieser aktiviert wird, wird der aktuelle Bildschirm gespeichert und durch den alternativen Bildschirm ersetzt. Das Speichern von Zeilen, die über den oberen Rand des Fensters gescrollt werden, ist deaktiviert, bis der normale Bildschirm wiederhergestellt ist. Der Eintrag term‐ cap(5) für xterm ermöglicht es dem visuellen Editor vi(1), zum Bearbeiten auf den alternativen Bildschirm umzuschalten 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_screenlistet einige Beispiele auf, wie Sie es selbst tun können, entweder übertputoder über einige Escape-Sequenzen.

Antwort2

Anstelle von „ echo, das automatisch eine neue Zeile an die Zeichenfolge anhängt, verwenden Sie „ printf "%s\r" whatever--“. Der Wagenrücklauf schickt den Cursor an den Anfang der aktuellen Zeile. Beispiel:

seq 1 15 | while read num; do printf "%2d\r" $num; sleep 1; done; echo ""

Antwort3

Ich würde auch denjenigen, die dieses Thema gefunden haben, empfehlen, einen Blick darauf zu werfenBash Prompt HOWTO - Cursorbewegung.

Beispiele:

- Position the Cursor:
  \033[<L>;<C>H
     Or
  \033[<L>;<C>f
  puts the cursor at line L and column C.
- Move the cursor up N lines:
  \033[<N>A
- Move the cursor down N lines:
  \033[<N>B
- Move the cursor forward N columns:
  \033[<N>C
- Move the cursor backward N columns:
  \033[<N>D

- Clear the screen, move to (0,0):
  \033[2J
- Erase to end of line:
  \033[K

- Save cursor position:
  \033[s
- Restore cursor position:
  \033[u

Einige Beispiele in C:

void saveCursorPosition() {
  printf("\033[s");
}

void restoreCursorPosition() {
  printf("\033[u");
}

void lineUP(short int times) {
  printf("\033[%iA", times);
}

void lineDown(short int times) {
  printf("\033[%iB", times);
}

Programmbeispiel:

#include <stdio.h>
#include <unistd.h>

void saveCursorPosition() {
  printf("\033[s");
}

void restoreCursorPosition() {
  printf("\033[u");
}

void lineUP(short int times) {
  printf("\033[%iA", times);
}

void moveCursorBackwards(short int times) {
  printf("\033[%iD", times);
}

void printMainText() {

  printf("\n ╔═══════════════════════════════╗");
  printf("\n ║                               ║");
  printf("\n ║ Progress Bar                  ║");
  printf("\n ║                               ║");
  printf("\n ║ []                            ║");
  printf("\n ║                               ║");
  printf("\n ║ Press Ctrl+C to close         ║");
  printf("\n ║                               ║");
  printf("\n ╚═══════════════════════════════╝\n");

}

int main(int argc, char **argv) {

  printMainText();

  for (int progress=0; progress <= 10; progress++) {

    saveCursorPosition();
    lineUP(5);

    printf("\r ║     [");
    fflush(stdout);

    for (int i=0; i<progress; i++) {
      printf("=>]");
      fflush(stdout);
      moveCursorBackwards(2);
    }

    moveCursorBackwards(progress + 5);

    printf("%i%%", progress * 10);
    fflush(stdout);

    restoreCursorPosition();

    sleep(1);

  }

  return 0;

}

verwandte Informationen