Wie kann ich die aktuell gedruckte Konsolenzeile in C löschen? Ich arbeite an einem Linux-System. Zum Beispiel -
printf("hello");
printf("bye");
Ich möchte Tschüss in derselben Zeile anstelle von Hallo drucken.
Wie kann ich die aktuell gedruckte Konsolenzeile in C löschen? Ich arbeite an einem Linux-System. Zum Beispiel -
printf("hello");
printf("bye");
Ich möchte Tschüss in derselben Zeile anstelle von Hallo drucken.
Antworten:
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:
printf("%c[2K", 27);
\r
ist daher weiterhin erforderlich. Beachten Sie, dass die Verwendung von %c
nicht erforderlich ist. Alternative:printf("\33[2K\r");
printf("\r ");
.
Mit einem \r
( Wagenrücklauf ) können Sie den Cursor an den Zeilenanfang zurücksetzen:
printf("hello");
printf("\rbye");
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:
printf("hello");
printf("\rbye ");
Oder löschen Sie es zuerst mit ein paar Leerzeichen und drucken Sie dann Ihre neue Zeichenfolge:
printf("hello");
printf("\r ");
printf("\rbye");
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 .
Einige lohnende Feinheiten ...
\33[2K
löscht die gesamte Zeile, in der sich Ihr Cursor gerade befindet
\033[A
Bewegt den Cursor um eine Zeile nach oben, jedoch in derselben Spalte, dh nicht zum Zeilenanfang
\r
bringt 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 fdfile
mit einem nicht blockierenden Dateideskriptor, den ich auf der Pseudo-Terminal-Adresse hatte (in meinem Fall /dev/pts/21
):
fprintf(fdfile, "\33[2K\rT minus %d seconds...", i);
fflush(fdfile);
Beachten Sie, dass ich sowohl die \ 33 [2K-Sequenz zum Löschen der Zeile als auch die \r
Wagenrü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:
fprintf(fdfile, "\033[A\33[2K\rT minus %d seconds...\n", i);
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:
i = 3;
fprintf(fdfile, "\nText to keep\n");
fprintf(fdfile, "Text to erase****************************\n");
while(i > 0) { // 3 second countdown
fprintf(fdfile, "\033[A\33[2KT\rT minus %d seconds...\n", i);
i--;
sleep(1);
}
\r
steht 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.
\33[2K
ist ein Weg zu gehen! Beste Problemlösung für mich. Funktioniert auch unter Windows ConEmu
Sie können die Zeile mit \ b löschen
printf("hello");
int i;
for (i=0; i<80; i++)
{
printf("\b");
}
printf("bye");
Wenn Sie am Ende der Zeichenfolge ein '\ r' haben, wird normalerweise nur der Wagenrücklauf ohne Zeilenumbruch gedruckt. Wenn Sie Folgendes haben:
printf("fooooo\r");
printf("bar");
Die Ausgabe lautet:
barooo
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:
char str[MAX_LENGTH];
// init str to all spaces, NULL terminated with character as '\r'
strcpy(str, my_string); // copy my_string into str
str[strlen(my_string)] = ' '; // erase null termination char
str[MAX_LENGTH - 1] = '\r';
printf(str);
Sie können eine Fehlerprüfung durchführen, so dass my_string
immer mindestens eine Länge weniger als ist str
, aber Sie erhalten die Grundidee.
i
iteriert durch char-Array-Wörter. j
Verfolgt die Wortlänge. "\b \b"
löscht das Wort beim Zurücksetzen über die Zeile.
#include<stdio.h>
int main()
{
int i = 0, j = 0;
char words[] = "Hello Bye";
while(words[i]!='\0')
{
if(words[i] != ' ') {
printf("%c", words[i]);
fflush(stdout);
}
else {
//system("ping -n 1 127.0.0.1>NUL"); //For Microsoft OS
system("sleep 0.25");
while(j-->0) {
printf("\b \b");
}
}
i++;
j++;
}
printf("\n");
return 0;
}
Dieses Skript ist für Ihr Beispiel fest codiert.
#include <stdio.h>
int main ()
{
//write some input
fputs("hello\n",stdout);
//wait one second to change line above
sleep(1);
//remove line
fputs("\033[A\033[2K",stdout);
rewind(stdout);
//write new line
fputs("bye\n",stdout);
return 0;
}
Klicken Sie hier für die Quelle .
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.
#include <iostream>
#include <string> //actually this thing is not nessasory in tdm-gcc
using namespace std;
int main(){
//create string variable
string str="Starting count";
//loop for printing numbers
for(int i =0;i<=50000;i++){
//get previous string length and clear it from screen with backspace charactor
cout << string(str.length(),'\b');
//create string line
str="Starting count " +to_string(i);
//print the new line in same spot
cout <<str ;
}
}
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.
int BlankBytes(int Bytes)
{
char strBlankStr[16];
sprintf(strBlankStr, "\r%%%is\r", Bytes);
printf(strBlankStr,"");
return 0;
}
int main(void)
{
int iBytesWritten;
double lfSomeDouble = 150.0;
iBytesWritten = printf("test text %lf", lfSomeDouble);
BlankBytes(iBytesWritten);
return 0;
}
Da ich VT100 nicht verwenden kann, muss ich mich anscheinend an diese Lösung halten
echo -e "hello\c" ;sleep 1 ; echo -e "\rbye "
Was der obige Befehl bewirkt:
Es wird Hallo gedruckt und der Cursor bleibt auf "o" (mit \ c)
Dann wartet es 1 Sekunde (Schlaf 1)
Dann wird Hallo durch Tschüss ersetzt (mit \ r)
NOTE : Using ";", We can run multiple command in a single go.
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:
#include <windows.h>
#include <iostream>
#define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004
#define DISABLE_NEWLINE_AUTO_RETURN 0x0008
int main(){
// enabling VT100 style in current console
DWORD l_mode;
HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
GetConsoleMode(hStdout,&l_mode)
SetConsoleMode( hStdout, l_mode |
ENABLE_VIRTUAL_TERMINAL_PROCESSING |
DISABLE_NEWLINE_AUTO_RETURN );
// create a waiting loop with changing text every seconds
while(true) {
// erase current line and go to line begining
std::cout << "\x1B[2K\r";
std::cout << "wait a second .";
Sleep(1);
std::cout << "\x1B[2K\r";
std::cout << "wait a second ..";
Sleep(1);
std::cout << "\x1B[2K\r";
std::cout << "wait a second ...";
Sleep(1);
std::cout << "\x1B[2K\r";
std::cout << "wait a second ....";
}
}
siehe folgenden Link: Windows VT100