C 清除当前打印的控制台行

C 清除当前打印的控制台行,c,linux,console,erase,C,Linux,Console,Erase,如何擦除C中当前打印的控制台行?我正在Linux系统上工作。例如— printf("hello"); printf("bye"); 我想在同一行上打印bye来代替hello。您可以使用\r()将光标返回到行的开头: printf("hello"); printf("\rbye"); 这将在同一行上打印bye。不过,它不会删除现有的字符,而且因为bye比hello短,所以最终将使用byelo。要删除它,您可以延长新打印的时间以覆盖额外的字符: printf("hello"); printf("

如何擦除C中当前打印的控制台行?我正在Linux系统上工作。例如—

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

我想在同一行上打印bye来代替hello。

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

printf("hello");
printf("\rbye");
这将在同一行上打印bye。不过,它不会删除现有的字符,而且因为bye比hello短,所以最终将使用byelo。要删除它,您可以延长新打印的时间以覆盖额外的字符:

printf("hello");
printf("\rbye  ");
或者,先用几个空格将其删除,然后打印新字符串:

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

这将打印hello,然后转到行首并用空格覆盖,然后再次返回行首并打印bye。

通常当字符串末尾有“\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
的长度至少少一个,但您可以得到基本的想法。

您可以使用\b删除该行

printf("hello");
int i;
for (i=0; i<80; i++)
{
  printf("\b");
}
printf("bye");
printf(“你好”);
int i;
对于(i=0;i您可以使用。大多数终端,包括xterm,都支持VT100。对于擦除线路,这是
^[[2K
。在C中,这给出了:

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

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;
}
#包括
int main()
{
int i=0,j=0;
char words[]=“你好,再见”;
while(单词[i]!='\0')
{
如果(字[i]!=''){
printf(“%c”,字[i]);
fflush(stdout);
}
否则{
//系统(“ping-n127.0.0.1>NUL”);//用于Microsoft操作系统
系统(“睡眠0.25”);
而(j-->0){
printf(“\b\b”);
}
}
i++;
j++;
}
printf(“\n”);
返回0;
}

此脚本是为您的示例而硬编码的

#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;
}
#包括
int main()
{
//写一些输入
fputs(“hello\n”,stdout);
//等一秒钟,换上面的线路
睡眠(1);
//拆线
FPUT(“\033[A\033[2K”,标准输出);
倒带(标准输出);
//写新行
fputs(“再见”,标准输出);
返回0;
}

单击此处查看。

一些有价值的细节

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

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

\r
将光标移到行的开头(r表示回车N.B.回车不包括换行符,因此光标保持在同一行),但不会擦除任何内容

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

在实现说明中,为了让它正常工作,例如在倒计时场景中,因为我没有使用新行字符
'\n'
在每个
fprintf()
的末尾,我每次都必须
fflush()
流(为了给您提供一些上下文,我在linux机器上使用fork启动了xterm,但没有重定向stdout,我只是用一个非阻塞文件描述符写入缓冲文件指针
fdfile
,该描述符位于伪终端地址上,在我的例子中是
/dev/pts/21
):

请注意,我使用了\33[2K序列来擦除紧跟着
\r
回车序列的行,以将光标重新定位在行的开头。我必须在每次
fprintf()之后执行
fflush()
因为我的结尾没有新行字符
“\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);
}

这里有一个简单的技巧,你可以在这里使用,但是在打印之前需要准备,你必须把你想要打印的内容放在一个变量中,然后打印,这样你就可以知道删除字符串的长度。下面是一个例子

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

}
#包括
#include//事实上,这件事在tdm gcc中是不必要的
使用名称空间std;
int main(){
//创建字符串变量
string str=“开始计数”;
//打印数字的循环

for(inti=0;i刚刚找到了这个旧线程,正在寻找某种转义序列来清空实际行

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

echo -e "hello\c" ;sleep 1 ; echo -e "\rbye  "
上述命令将执行的操作:

  • 它将打印hello,光标将保持在“o”(使用\c)

  • 然后它将等待1秒(睡眠1)

  • 然后它将用bye替换hello。(使用\r)


  • 注意:使用“;”,我们可以一次运行多个命令。

    在windows 10下,可以通过激活当前控制台中的VT100模式来使用VT100样式,以使用转义序列,如下所示:

    #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 ....";
     }
    
    }
    
    #包括
    #包括
    #定义启用虚拟终端处理0x0004
    #定义
    
    #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 ....";
     }
    
    }