Löschen Sie die aktuell gedruckte Konsolenzeile

72

Wie kann ich die aktuell gedruckte Konsolenzeile in C löschen? Ich arbeite an einem Linux-System. Zum Beispiel -

Ich möchte Tschüss in derselben Zeile anstelle von Hallo drucken.

MD XF
quelle
1
Die ncurses-Bibliothek wird dies wahrscheinlich tun. Ich weiß es nicht gut genug, um eine Antwort zu geben, aber hier sind Links zu Dokumenten und einer verwandten Frage . Dieser Kommentar basiert auf der Antwort von Wil Shipley aus dem Jahr 2009, die möglicherweise gelöscht wird.
Tom Zych

Antworten:

72

Sie können VT100-Escape-Codes verwenden . Die meisten Terminals, einschließlich xterm, sind VT100-fähig. Zum Löschen einer Zeile ist dies ^[[2K. In C ergibt dies:

Mouviciel
quelle
52
Dies setzt den Cursor nicht auf den Zeilenanfang zurück (zumindest in meinem Terminal) und \rist daher weiterhin erforderlich. Beachten Sie, dass die Verwendung von %cnicht erforderlich ist. Alternative:printf("\33[2K\r");
Stephan202
5
Nur ein kleiner Hinweis, dass die ANSI-Formatierung in Windows nicht unterstützt wird ( ANSI-Escape-Code ). Aber es ist immer noch möglich zu verwenden printf("\r ");.
CocoaBob
2
@CocoaBob Das hat sich seit dem Windows 10 Update TH2 geändert .
Hydranix
1
Es funktioniert nicht unter Windows vor Windows 10
Phuclv
1
@ LưuVĩnhPhúc - Frage endet mit: Ich arbeite an einem Linux-System
Mouviciel
57

Mit einem \r( Wagenrücklauf ) können Sie den Cursor an den Zeilenanfang zurücksetzen:

Dies wird Tschüss in derselben Zeile drucken . Die vorhandenen Zeichen werden jedoch nicht gelöscht, und da bye kürzer als hallo ist , erhalten Sie byelo . Um es zu löschen, können Sie Ihren neuen Druck verlängern, um die zusätzlichen Zeichen zu überschreiben:

Oder löschen Sie es zuerst mit ein paar Leerzeichen und drucken Sie dann Ihre neue Zeichenfolge:

Das wird Hallo drucken , dann zum Anfang der Zeile gehen und sie mit Leerzeichen überschreiben, dann wieder zum Anfang zurückkehren und Tschüss drucken .

Andre Miller
quelle
45

Einige lohnende Feinheiten ...

\33[2K löscht die gesamte Zeile, in der sich Ihr Cursor gerade befindet

\033[ABewegt den Cursor um eine Zeile nach oben, jedoch in derselben Spalte, dh nicht zum Zeilenanfang

\rbringt Sie den Cursor von der Zeile an den Anfang (r für Wagenrücklauf NB Zeilenumbrüche enthalten keine Newline so auf der gleichen Linie Cursor bleibt) , aber nicht der Fall ist alles gelöscht ,

Insbesondere in xterm habe ich die oben genannten Antworten ausprobiert. Die einzige Möglichkeit, die Zeile zu löschen und am Anfang erneut zu beginnen, ist die Sequenz (aus dem obigen Kommentar von @ Stephan202 sowie @vlp und @mantal). \33[2K\r

Um die Implementierung zum Beispiel in einem Countdown-Szenario ordnungsgemäß zu gestalten, da ich '\n' am Ende jedes Zeichens kein neues Zeilenzeichen verwendet fprintf()habe, musste ich fflush()jedes Mal den Stream verwenden (um Ihnen einen Kontext zu geben, habe ich begonnen xterm mit einem Fork auf einem Linux-Rechner ohne Umleitung von stdout schrieb ich gerade in den gepufferten FILE-Zeiger fdfilemit einem nicht blockierenden Dateideskriptor, den ich auf der Pseudo-Terminal-Adresse hatte (in meinem Fall /dev/pts/21):

Beachten Sie, dass ich sowohl die \ 33 [2K-Sequenz zum Löschen der Zeile als auch die \rWagenrücklaufsequenz verwendet habe, um den Cursor am Zeilenanfang neu zu positionieren. Ich musste fflush()nach jedem, fprintf()weil ich am Ende kein neues Zeilenzeichen habe '\n'. Das gleiche Ergebnis ohne fflush () würde die zusätzliche Sequenz erfordern, um eine Zeile nach oben zu gehen:

Beachten Sie, dass wenn Sie etwas in der Zeile unmittelbar über der Zeile haben, in die Sie schreiben möchten, es mit dem ersten fprintf () überschrieben wird. Sie müssten eine zusätzliche Zeile darüber lassen, um die erste Bewegung um eine Zeile nach oben zu ermöglichen:

Janus
quelle
3
\rsteht für "Wagenrücklauf", nicht für "Zurückspulen" und ist ein Relikt guter alter Schreibmaschinen, die separate Operationen für "Cursor zurück in die erste Spalte bewegen" ( \r) und "Seite zur nächsten Zeile vorrücken" ( \n) hatten.
Ijustlovemath
1
\33[2Kist ein Weg zu gehen! Beste Problemlösung für mich. Funktioniert auch unter Windows ConEmu
Grzegorz
Aus irgendeinem Grund funktionieren all diese wunderbaren Antworten für mich einfach nicht, wenn ich eine einfache ausführbare C-Datei auf meinem MacOS in Terminal ausführe (bash, zsh was auch immer). Ich bekomme alle möglichen seltsamen Verhaltensweisen und seltsame Zeichen (oder gar nichts) gedruckt, aber niemals die klare Linie als das
Überdrucken
4

Sie können die Zeile mit \ b löschen

Alexander Egger
quelle
6
Bewegt \ b den Cursor nicht einfach um ein Zeichen zurück? Die Charaktere werden immer noch da sein. Ich denke du könntest so etwas wie "\ b \ b" machen.
Andre Miller
Auf meiner Linux-Box wird die Zeile gelöscht. Möglicherweise ist das Verhalten auf anderen Plattformen anders.
Alexander Egger
3

Wenn Sie am Ende der Zeichenfolge ein '\ r' haben, wird normalerweise nur der Wagenrücklauf ohne Zeilenumbruch gedruckt. Wenn Sie Folgendes haben:

Die Ausgabe lautet:

Eine Sache, die ich vorschlagen kann (möglicherweise eine Problemumgehung), besteht darin, eine NULL-terminierte Zeichenfolge mit fester Größe zu haben, die mit allen Leerzeichen initialisiert wird und jedes Mal vor dem Drucken mit einem '\ r' endet, und dann strcpy zum Kopieren Ihrer Zeichenfolge zu verwenden es (ohne die neue Zeile), so dass jeder nachfolgende Druck die vorherige Zeichenfolge überschreibt. Etwas wie das:

Sie können eine Fehlerprüfung durchführen, so dass my_stringimmer mindestens eine Länge weniger als ist str, aber Sie erhalten die Grundidee.

Ashwin
quelle
2

iiteriert durch char-Array-Wörter. jVerfolgt die Wortlänge. "\b \b"löscht das Wort beim Zurücksetzen über die Zeile.

Paul T.
quelle
2

Dieses Skript ist für Ihr Beispiel fest codiert.

Klicken Sie hier für die Quelle .

vlp
quelle
1

Es gibt einen einfachen Trick, den Sie hier ausführen können, der jedoch vor dem Drucken vorbereitet werden muss. Sie müssen alles, was Sie drucken möchten, in eine Variable einfügen und dann drucken, damit Sie die Länge zum Entfernen der Zeichenfolge kennen. Es gibt ein Beispiel.

Aylian Craspa
quelle
0

Ich habe gerade diesen alten Thread gefunden und nach einer Art Escape-Sequenz gesucht, um die eigentliche Zeile auszublenden.

Es ist ziemlich lustig, dass niemand auf die Idee gekommen ist (oder ich habe es verpasst), dass printf die Anzahl der geschriebenen Zeichen zurückgibt. Drucken Sie also einfach '\ r' + so viele leere Zeichen, wie printf zurückgegeben hat, und Sie werden den zuvor geschriebenen Text genau leer lassen.

Da ich VT100 nicht verwenden kann, muss ich mich anscheinend an diese Lösung halten

David
quelle
0

Was der obige Befehl bewirkt:

  1. Es wird Hallo gedruckt und der Cursor bleibt auf "o" (mit \ c)

  2. Dann wartet es 1 Sekunde (Schlaf 1)

  3. Dann wird Hallo durch Tschüss ersetzt (mit \ r)

NOTE : Using ";", We can run multiple command in a single go.

Ayush Mahajan
quelle
Dies ist Bash, nicht C
Orgg vor
0

Unter Windows 10 kann der VT100-Stil verwendet werden, indem der VT100-Modus in der aktuellen Konsole aktiviert wird, um Escape-Sequenzen wie folgt zu verwenden:

siehe folgenden Link: Windows VT100

user2019716
quelle