Стереть текущую напечатанную строку консоли - PullRequest
56 голосов
/ 02 октября 2009

Как стереть текущую напечатанную консольную строку в C? Я работаю в системе Linux. Например -

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

Я хочу напечатать пока на той же строке вместо Привет.

Ответы [ 9 ]

58 голосов
/ 02 октября 2009

Вы можете использовать escape-коды VT100 . Большинство терминалов, включая xterm, поддерживают VT100. Для удаления линии это ^[[2K. В Си это дает:

printf("%c[2K", 27);
52 голосов
/ 02 октября 2009

Вы можете использовать \r ( возврат каретки ), чтобы вернуть курсор в начало строки:

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

Это напечатает пока в той же строке. Однако он не сотрет существующие символы, и, поскольку пока короче, чем привет , вы получите byelo . Чтобы стереть его, вы можете сделать новый отпечаток длиннее, чтобы перезаписать дополнительные символы:

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

Или сначала сотрите его несколькими пробелами, а затем напечатайте новую строку:

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

Будет напечатано привет , затем перейдите к началу строки и перезапишите ее пробелами, затем снова вернитесь к началу и напечатайте пока .

32 голосов
/ 04 февраля 2016

Некоторые стоящие тонкости ...

\33[2K стирает всю строку, на которой находится ваш курсор

\033[A перемещает курсор вверх на одну строку, но в том же столбце , т.е. не до начала строки

\r переводит курсор в начало строки (r для перемотки назад), но не ничего не стирает

В частности, в xterm я попробовал ответы, упомянутые выше, и единственный найденный способ стереть строку и начать заново в начале - это последовательность (из приведенного выше комментария @ Stephan202, а также @vlp и @mantal) \33[2K\r

В примечании к реализации, чтобы заставить его работать должным образом, например, в сценарии обратного отсчета, поскольку я не использовал символ новой строки '\n' в конце каждого fprintf(), поэтому мне приходилось каждый раз fflush() поток (чтобы дать вам некоторый контекст, я запустил xterm, используя форк на машине с Linux без перенаправления stdout, я просто записывал в буферизованный указатель FILE fdfile с неблокирующим файловым дескриптором, который я сидел по адресу псевдотерминала, который в моем случае был /dev/pts/21):

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

Обратите внимание, что я использовал последовательность \ 33 [2K, чтобы стереть строку, за которой следует последовательность перемотки \r, чтобы переместить курсор в начало строки. Мне нужно было fflush() после каждого fprintf(), потому что у меня нет символа новой строки в конце '\n'. Тот же результат без использования fflush () потребует дополнительной последовательности для перехода вверх по строке:

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

Обратите внимание, что если у вас есть что-то в строке сразу над строкой, в которую вы хотите записать, это будет перезаписано с первой функцией fprintf (). Вы должны были бы оставить дополнительную строку выше, чтобы учесть первое движение вверх на одну строку:

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);
}
4 голосов
/ 02 октября 2009

Вы можете удалить строку, используя \ b

printf("hello");
int i;
for (i=0; i<80; i++)
{
  printf("\b");
}
printf("bye");
3 голосов
/ 02 октября 2009

Обычно, когда в конце строки стоит символ «\ r», печатается только возврат каретки без перевода строки. Если у вас есть следующее:

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

вывод будет:

barooo

Одна вещь, которую я могу предложить (возможно, в качестве обходного пути), это иметь строку фиксированного размера с завершающей строкой NULL, которая инициализируется всеми пробелами, заканчивающимися символом '\ r' (каждый раз перед печатью), а затем использовать strcpy для копирования Ваша строка в него (без перевода строки), поэтому каждый последующий вывод будет перезаписывать предыдущую строку. Примерно так:

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

Вы можете выполнить проверку ошибок, чтобы my_string всегда был как минимум на одну длину меньше, чем str, но вы получили основную идею.

2 голосов
/ 18 февраля 2012

i перебирает слова массива символов. j отслеживает длину слова. "\b \b" стирает слово при отступе через строку.

#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;
}
1 голос
/ 29 марта 2016

есть простой трюк, с которым вы можете здесь поработать, но перед печатью его нужно подготовить, вы должны поместить в переменную то, что вы хотите напечатать, а затем распечатать, чтобы вы знали длину удаления строки. пример.

#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 голос
/ 14 июля 2015

Этот скрипт жестко запрограммирован для вашего примера.

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

Нажмите здесь для источника .

0 голосов
/ 01 февраля 2018

Только что нашел этот старый поток, искал какую-то escape-последовательность, чтобы очистить фактическую строку.

Довольно забавно, что никто не пришел к мысли (или я пропустил это), что printf возвращает количество написанных символов. Поэтому просто напечатайте '\ r' + столько пустых символов, сколько вернуло printf, и вы точно очистите предыдущий текст.

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

Поскольку я не могу использовать VT100, похоже, мне нужно придерживаться этого решения

...