如何在C中删除当前打印的控制台线?我正在研究Linux系统。例如 -
printf("hello");
printf("bye");
我想在同一行打印再见代替你好。
答案 0 :(得分:57)
您可以使用VT100 escape codes。大多数终端,包括xterm,都知道VT100。要删除一行,这是^[[2K
。在C中,这给出了:
printf("%c[2K", 27);
答案 1 :(得分:52)
您可以使用\r
(carriage return)将光标返回到行首:
printf("hello");
printf("\rbye");
这将在同一行打印 bye 。它不会删除现有的字符,因为 bye 比 hello 短,所以最终会使用 byelo 。要删除它,您可以延长新的打印时间以覆盖额外的字符:
printf("hello");
printf("\rbye ");
或者,首先用几个空格擦除它,然后打印新的字符串:
printf("hello");
printf("\r ");
printf("\rbye");
那将打印 hello ,然后转到行的开头并用空格覆盖它,然后再次返回到开头并打印 bye 。
答案 2 :(得分:30)
一些有价值的细微之处......
\33[2K
删除光标当前所在的整行
\033[A
将光标向上移动一行,但在同一列中,即不在行的开头
\r
将光标移至线的开头(r代表倒带),但不会删除任何内容
特别是在xterm中,我尝试了上面提到的回复,我发现删除行并在开头重新开始的唯一方法是序列(来自@ Stephan202以及@vlp和@mantal发布的上述评论) \33[2K\r
在实施说明中,为了使其正常工作,例如在倒计时场景中,因为我没有使用换行符'\n'
在每个fprintf()
的末尾,所以每次我必须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);
}
答案 3 :(得分:4)
您可以使用\ b
删除该行printf("hello");
int i;
for (i=0; i<80; i++)
{
printf("\b");
}
printf("bye");
答案 4 :(得分:3)
通常当字符串末尾有'\ 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
,但您可以获得基本的想法。
答案 5 :(得分:2)
i
遍历char数组字。 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;
}
答案 6 :(得分:1)
此脚本是针对您的示例进行硬编码的。
#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。
答案 7 :(得分: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 ;
}
}
答案 8 :(得分:0)
刚刚找到这个旧线程,寻找某种转义序列来清空实际行。
很有趣,没有人知道(或者我错过了)printf返回写入的字符数。所以只需打印&#39; \ r&#39; +返回与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,似乎我必须坚持使用该解决方案
答案 9 :(得分:0)
echo -e "hello\c" ;sleep 1 ; echo -e "\rbye "
以上命令将执行的操作:
它将打印问候,并且光标将停留在“ o”(使用\ c)
然后它将等待1秒钟(睡眠1)
然后它将用再见替换问候。(使用\ r)
NOTE : Using ";", We can run multiple command in a single go.
答案 10 :(得分:0)
在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 ....";
}
}
请参阅以下链接:windows VT100
答案 11 :(得分:0)
其他人已经回答了 OP 的问题。对于那些想知道为什么回车在他们的 Linux 机器上的行为方式的人来说,这是一个答案 -
回车符的行为似乎是平台相关的。
来自 C11 标准的“5.2.2 字符显示语义”部分:
<块引用>\r (回车) 将活动位置移动到初始位置 当前行。
来自 POSIX 标准 (https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html) 的“3.86 Carriage-Return Character (<回车符>)”部分:
<块引用>在输出流中指示打印的字符 从同一物理行的开头开始 发生回车。是'\r'中指定的字符 C语言。未指定此字符是否准确 由系统传送到输出设备的序列以完成 移动到行首。
它没有说明回车是否应该擦除(=> 用 NUL 字符填充)整行。我的猜测是它不应该擦除。
然而,在我的 Linux 机器上(在 x86_64 和 ARM32 上都尝试过),我观察到的是回车符将光标移动到当前行的开头,并且还用 '\0' 字符(NUL人物)。为了注意到这些 NUL 字符,您可能必须直接从代码中调用 write 系统调用,而不是通过 glibc printf 调用。
我们以下面的代码片段为例:
printf("hello");
printf("\rbye");
在 beaglebone black(32 位 ARM)bash 终端上构建和运行它:
ubuntu@arm:~$ ./a.out
byeubuntu@arm:~$
写入系统调用的跟踪输出:
bye) = 9 9hello
+++ exited with 4 +++