web-dev-qa-db-fra.com

Effacer la ligne de console imprimée actuelle

Comment puis-je effacer la ligne actuelle de la console imprimée en C? Je travaille sur un système Linux. Par exemple - 

printf("hello");
printf("bye");

Je veux imprimer au revoir sur la même ligne au lieu de bonjour.

51
Peter

Vous pouvez utiliser les codes d'échappement VT100 . La plupart des terminaux, y compris xterm, sont compatibles VT100. Pour effacer une ligne, il s'agit de ^[[2K. En C cela donne:

printf("%c[2K", 27);
54
mouviciel

Vous pouvez utiliser un \r ( retour de chariot ) pour ramener le curseur au début de la ligne:

printf("hello");
printf("\rbye");

Ceci imprimera bye sur la même ligne. Cela n'effacera pas les caractères existants, et comme bye est plus court que hello, vous obtiendrez byelo. Pour l'effacer, vous pouvez rallonger votre nouvelle impression et écraser les caractères supplémentaires:

printf("hello");
printf("\rbye  ");

Ou, effacez-le d'abord avec quelques espaces, puis imprimez votre nouvelle chaîne:

printf("hello");
printf("\r          ");
printf("\rbye");

Cela imprimera hello, puis ira au début de la ligne et la remplacera par des espaces, puis reviendra au début et imprimera bye.

52
Andre Miller

Quelques subtilités intéressantes ...

\33[2K efface toute la ligne sur laquelle se trouve votre curseur

\033[A déplace votre curseur d'une ligne vers le haut, mais dans la même colonne c'est-à-dire pas au début de la ligne

\r amène votre curseur au début de la ligne (r est pour rembobiner) mais ne pas efface quoi que ce soit

Dans xterm en particulier, j’ai essayé les réponses mentionnées ci-dessus et le seul moyen que j’ai trouvé pour effacer la ligne et recommencer au début est la séquence (tirée du commentaire ci-dessus posté par @ Stephan202 ainsi que @vlp et @mantal) \33[2K\r

Sur une note d’implémentation, pour que cela fonctionne correctement, par exemple dans un scénario de compte à rebours car je n’utilisais pas le nouveau caractère de ligne '\n'à la fin de chaque fprintf(), je devais donc fflush() le flux à chaque fois (pour vous avez un peu de contexte, j’ai commencé xterm en utilisant un fork sur une machine Linux sans rediriger stdout, j’écrivais juste d’écrire sur le pointeur FILE tamponné fdfile avec un descripteur de fichier non bloquant que j’étais assis sur la pseudo-adresse de terminal qui était dans mon cas /dev/pts/21) :

fprintf(fdfile, "\33[2K\rT minus %d seconds...", i);
fflush(fdfile);

Notez que j’ai utilisé la séquence\33 [2K pour effacer la ligne suivie de la séquence de rembobinage \r pour repositionner le curseur au début de la ligne. Je devais fflush() après chaque fprintf() car je n'ai pas de caractère de nouvelle ligne à la fin '\n'. Le même résultat sans avoir besoin de fflush () nécessiterait la séquence supplémentaire pour remonter une ligne:

fprintf(fdfile, "\033[A\33[2K\rT minus %d seconds...\n", i);

Notez que si vous avez quelque chose sur la ligne immédiatement au-dessus de la ligne sur laquelle vous voulez écrire, il sera écrasé par le premier fprintf (). Vous devez laisser une ligne supplémentaire au-dessus pour permettre le premier mouvement d'une ligne:

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);
}
25
J-a-n-u-s

Vous pouvez supprimer la ligne en utilisant\b

printf("hello");
int i;
for (i=0; i<80; i++)
{
  printf("\b");
}
printf("bye");
4
alexander.egger

Habituellement, lorsque vous avez un '\ r' à la fin de la chaîne, seul le retour à la ligne est imprimé sans nouvelle ligne. Si vous avez ce qui suit:

printf("fooooo\r");
printf("bar");

la sortie sera:

barooo

Une chose que je peux suggérer (peut-être une solution de contournement) est d’avoir une chaîne de taille fixe terminée par la valeur NULL initialisée à tous les espaces, se terminant par un '\ r' (à chaque fois avant l’impression), puis d’utiliser strcpy pour copier votre chaîne dans (sans la nouvelle ligne), ainsi chaque impression ultérieure écrasera la chaîne précédente. Quelque chose comme ça:

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);

Vous pouvez vérifier les erreurs pour que my_string ait toujours au moins une longueur inférieure à str, mais vous obtenez l’idée de base.

3
Ashwin

i itère à travers les mots du tableau de caractères. j garde la trace de la longueur de Word. "\b \b" efface Word lors du recul de la ligne.

#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;
}
2
Paul T

Ce script est codé en dur pour votre exemple.

#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;
}

Cliquez ici pour source .

1
vlp

il existe une astuce simple qui vous permet de travailler ici, mais vous devez vous préparer avant d’imprimer, vous devez mettre ce que vous voulez imprimer dans une variable, puis l’imprimer pour que vous sachiez la longueur nécessaire pour supprimer la chaîne.

#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 ;
    }

}
1
Aylian Craspa

sous Windows 10, vous pouvez utiliser le style VT100 en activant le mode VT100 dans la console actuelle pour utiliser les séquences d'échappement suivantes:

#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 ....";
 }

}

voir le lien suivant: windows VT1

0
user2019716

Je viens de trouver ce vieux fil, à la recherche d'une sorte de séquence d'échappement pour effacer la ligne réelle. 

C'est assez marrant que personne ne vienne à l'idée (ou je l'ai manquée) que printf renvoie le nombre de caractères écrits. Il suffit donc d’imprimer '\ r' + autant de caractères vierges que printf est retourné et vous effacerez exactement le texte précédemment écrit.

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;
}

Comme je ne peux pas utiliser le VT100, il me semble que je dois rester avec cette solution

0
David
echo -e "hello\c" ;sleep 1 ; echo -e "\rbye  "

Que fera la commande ci-dessus:

  1. Il imprimera bonjour et le curseur restera à "o" (avec\c)

  2. Ensuite, il attendra 1 seconde (sommeil 1)

  3. Ensuite, il remplacera salut par bye. (En utilisant\r)

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

0
Ayush Mahajan