我正在编写一个命令行程序,它将有一个状态栏,就像wget。
我面临的主要问题是:如何删除已经发送到stdout / stderr的内容?
我有点想法:使用退格字符'\ b'并删除我发送的输出。这是最好的方式吗?这是唯一的方法吗?还有更好的方法吗?
PS:我不想使用像ncurses这样的东西。平原老C请。
由于
编辑:
我也可以上/下吗?示例:我有10行输出,我想将第3行从Doing ABC
更改为ABC: Done
。我怎么能这样做?
此外,任何人都可以发布有关VT102字符的更多详细信息吗?它的功能是什么?如果您有任何链接,请在此发布好的链接。
由于
答案 0 :(得分:6)
基本格式控制字符是退格键(\ b),制表符(\ t),换行符(\ n)和回车符(\ r \ n)。如果您需要更多,那么您可以使用ANSI X3.64 / ISO / IEC 6429 / ECMA-48转义序列;大多数现代终端和仿真器都认可至少the VT100 subset。使用ncurses的一个优点是它将查找特定终端的功能,因此即使您的终端使用不同的转义序列集也能正常工作。
答案 1 :(得分:5)
您必须记住,就常规stdio例程而言,stdout
只是一个字节流,没有固有的显示特性;这取决于目标设备,可以是从常规VT100风格的终端到硬拷贝终端,到单张纸打印机,到绘图仪等等。
IMO,你远使用像ncurses
这样的库比尝试用VT100转义代码破解你自己的显示管理代码更好,即使对于像这样的相对简单的任务。我知道你想坚持使用“普通老C”,但这是一项超出普通老C范围的任务。
答案 2 :(得分:3)
使用'\ r'返回行的开头并可能重写整行。
寻找VT102控制序列 - 这些是字符序列ESC ...来控制你的终端。
答案 3 :(得分:2)
还有可能使用Ncurses,它是Textual UI的库,这种行为应该有一些支持。但是,这样的事情可能有点过分。
答案 4 :(得分:1)
您自己的解决方案略有不同:
您还可以打印回车符(\r
),它将返回到行的开头。
答案 5 :(得分:0)
这是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""%";
}
答案 6 :(得分:0)
关于进度条:这样的事情?
#include <stdio.h>
#include <unistd.h>
typedef enum
{
false=0,
true=!false
} bool;
typedef struct
{
/* Start delimiter (e.g. [ )*/
char StartDelimiter;
/* End Delimiter (e.g. ] )*/
char EndDelimiter;
/* Central block (e.g. = )*/
char Block;
/* Last block (e.g. > ) */
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新手。