it-swarm.dev

擦除当前打印的控制台线

如何在C中删除当前打印的控制台线?我正在研究Linux系统。例如 -

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

我想在同一行打印再见代替你好。

54
Peter

您可以使用 VT100转义码 。大多数终端,包括xterm,都知道VT100。为了擦除一行,这是^[[2K。在C中,这给出:

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

您可以使用\r回车 )将光标返回到行的开头:

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

这将在同一行打印 bye 。它不会删除现有的字符,因为 bye hello 更短,你最终会得到 byelo 。要删除它,您可以延长新的打印时间以覆盖额外的字符:

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

或者,首先用几个空格擦除它,然后打印新的字符串:

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

这将打印 hello ,然后转到行的开头并用空格覆盖它,然后再次返回到开头并打印 bye

52
Andre Miller

一些有价值的细微之处......

\33[2K删除光标当前所在的整行

\033[A将光标向上移动一行,但在 同一列 即不到行的开头

\r将光标移到行的开头(r用于倒带)但是 不会 擦除任何内容

特别是在xterm中,我尝试了上面提到的回复,我发现删除行并在开头重新开始的唯一方法是序列(来自@ Stephan202以及@vlp和@mantal发布的上述评论)\33[2K\r

在实现说明中,为了让它在倒计时场景中正常工作,因为我没有在每个fprintf()的末尾使用新的行字符'\n',所以每次都必须fflush()流(给你一些上下文) ,我在Linux机器上使用fork启动xterm而不重定向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);
}
30
J-a-n-u-s

您可以使用\ b删除该行

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

通常当字符串末尾有'\ 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长一个,但是你得到了基本的想法。

3
Ashwin

i遍历char数组字。 j跟踪字长。 "\b \b"在删除行时删除Word。

#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

此脚本是硬编码的示例。

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

单击此处获取 source

1
vlp

有一个简单的技巧,你可以在这里工作,但它需要准备打印之前,你必须把你想要的东西打印在一个变量然后打印,这样你就会知道删除字符串的长度。这是一个例子。

#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

刚刚找到这个旧线程,寻找某种转义序列来清空实际行。

很有趣的是,没有人知道(或者我已经错过了)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,似乎我必须坚持使用该解决方案

0
David