擦除linux上的terminal输出

我正在写一个命令行程序,它将有一个状态栏,很像wget。

我面临的主要问题是:如何删除已经发送到stdout / stderr的内容?

我有想法:使用退格字符'\ B'和擦除我已经发送的输出。 这是最好的方法吗? 这是唯一的方法吗? 有没有更好的办法?

PS:我不想使用像ncurses这样的东西。 简单的老C请。

谢谢


编辑:

我也可以上去和/或下去吗? 例如:我有10行输出,我想把第三行从Doing ABC做到ABC: Done 。 我怎样才能做到这一点?

另外,任何人都可以发布有关VT102字符的更多细节? 它有什么function? 如果您有任何问题,请发布好的链接。

谢谢

使用'\ r'返回到行的开头,并可能重写整行。

寻找VT102控制序列 – 这些是字符序列ESC …来控制您的终端。

基本格式控制字符是退格符(\ b),制表符(\ t),换行符(\ n)和回车符(\ r)。 如果您需要更多,那么您可以使用ANSI X3.64 / ISO / IEC 6429 / ECMA-48转义序列; 至少VT100子集被大多数现代终端和仿真器识别。 使用ncurses的一个优点是,它将查找特定终端的功能,因此即使您的终端使用不同的转义序列集,它也能正常工作。

你必须记住,就常规的stdio例程而言, stdout只是一个没有固有显示特性的字节流; 这取决于目标设备,它可以是从常规的VT100型终端到硬拷贝终端到单张打印机到绘图仪的任何事物。

国际海事组织(IMO),使用像ncurses这样的库比使用VT100转义代码将自己的显示管理代码拼凑在一起更好,即使是像这样一个相对简单的任务。 我知道你想坚持“普通老C”,但这是一个超出普通老C的范围之外的任务。

也有可能使用Ncurses ,这是一个文本用户界面的库,这种行为应该有一定的支持。 然而,这可能是矫枉过正的。

你自己的解决方案略有变化:

您也可以打印回车( \r ),这将返回到行的开始。

这是一个bash的进度条。

 function gauge() { progress="$1" total="$2" width=`tput cols` let gwidth=width-7 if [ "$total" == "0" ]; then percent=100 else set +e let percent=progress*100/total; set -e fi set +e let fillcount=percent*gwidth/100 let nofillcount=gwidth-fillcount set -e fill=""; if [ "$fillcount" -gt "0" ]; then for i in `seq $fillcount`; do fill="$fill""|" done fi; nofill="" if [ "$nofillcount" -gt "0" ]; then for i in `seq $nofillcount`; do nofill="$nofill"" "; done fi echo -e -n "\r[""$fill""$nofill""] ""$percent""%"; } 

关于进度条:这样的事情?

 #include <stdio.h> #include <unistd.h> typedef enum { false=0, true=!false } bool; typedef struct { /* Start delimiter (eg [ )*/ char StartDelimiter; /* End Delimiter (eg ] )*/ char EndDelimiter; /* Central block (eg = )*/ char Block; /* Last block (eg > ) */ char CurBlock; /* Width of the progress bar (in characters) */ unsigned int Width; /* Maximum value of the progress bar */ double Max; /* True if we have to print also the percentage of the operation */ bool PrintPercentage; /* True if the bar must be redrawn; note that this must be just set to false before the first call, the function then will change it by itself. */ bool Update; } ProgressBarSettings; /* Prints/updates the progress bar */ void PrintProgressBar(double Pos, ProgressBarSettings * Settings); /* Inits the settings of the progress bar to the default values */ void DefaultProgressBar(ProgressBarSettings * Settings); int main() { int i; /* Init the bar settings */ ProgressBarSettings pbs; DefaultProgressBar(&pbs); pbs.Max=200; pbs.Width=60; printf("Progress: "); /* Show the empty bar */ PrintProgressBar(0,&pbs); for(i=0;i<=pbs.Max;i++) { /* Wait 50 msec */ usleep(50000); /* Update the progress bar */ PrintProgressBar(i,&pbs); } puts(" Done"); return 0; } /* Inits the settings of the progress bar to the default values */ void DefaultProgressBar(ProgressBarSettings * Settings) { Settings->StartDelimiter='['; Settings->EndDelimiter=']'; Settings->Block='='; Settings->CurBlock='>'; Settings->PrintPercentage=true; Settings->Update=false; Settings->Max=100; Settings->Width=40; } /* Prints/updates the progress bar */ void PrintProgressBar(double Pos, ProgressBarSettings * Settings) { /* Blocks to print */ unsigned int printBlocks=(unsigned int)(Settings->Width*Pos/Settings->Max); /* Counter */ unsigned int counter; /* If we are updating an existing bar...*/ if(Settings->Update) { /* ... we get back to its first character to rewrite it... */ for(counter=Settings->Width+2+(Settings->PrintPercentage?5:0);counter;counter--) putchar('\b'); } else Settings->Update=true; /* next time we'll be updating it */ /* Print the first delimiter */ putchar(Settings->StartDelimiter); /* Reset the counter */ counter=Settings->Width; /* Print all the blocks except the last; in the meantime, we decrement the counter, so in the end we'll have the number of spaces to fill the bar */ for(;printBlocks>1;printBlocks--,counter--) putchar(Settings->Block); /* Print the last block; if the operation ended, use the normal block, otherwise the one for the last block */ putchar((Settings->Max==Pos)?Settings->Block:Settings->CurBlock); /* Another block was printed, decrement the counter */ counter--; /* Fill the rest of the bar with spaces */ for(;counter;counter--) putchar(' '); /* Print the end delimiter */ putchar(Settings->EndDelimiter); /* If asked, print also the percentage */ if(Settings->PrintPercentage) printf(" %3d%%",(int)(100*Pos/Settings->Max)); /* Flush the output buffer */ fflush(stdout); }; 

注意:unistd.h和usleep只是伪造一个操作的进度,进度条本身就是使用标准库。 它对输出流的唯一假设是\ b实际上到达了前面写的字符。 我在Windows和Linux(使用gnome-terminal)上成功尝试了它,不知道它是否在一些终端仿真器上无法正常工作。 对于过多的评论感到抱歉,我写了另一个论坛,我需要实际解释每一行的C新手。