如何animation命令行?

我一直想知道人们如何更新命令行中的上一行。 一个很好的例子是在linux中使用wget命令。 它创build一个类似于这样的ASCII加载栏:

[======>] 37%

当然,加载栏移动和百分比变化,但它并没有一个新的路线。 我无法弄清楚如何做到这一点。 有人能指出我正确的方向吗?

我知道有两种方法可以做到这一点:

  • 使用退格转义字符('\ b')擦除您的行
  • 使用curses包,如果你select的编程语言已经绑定了它。

谷歌公布的ANSI逃逸代码似乎是一个好方法。 作为参考,这里是一个在C ++中的function来做到这一点:

 void DrawProgressBar(int len, double percent) { cout << "\x1B[2K"; // Erase the entire current line. cout << "\x1B[0E"; // Move to the beginning of the current line. string progress; for (int i = 0; i < len; ++i) { if (i < static_cast<int>(len * percent)) { progress += "="; } else { progress += " "; } } cout << "[" << progress << "] " << (static_cast<int>(100 * percent)) << "%"; flush(cout); // Required. } 

一种方法是用当前进度重复更新文本行。 例如:

 def status(percent): sys.stdout.write("%3d%%\r" % percent) sys.stdout.flush() 

请注意,我使用sys.stdout.write而不是print (这是Python),因为print在每行的末尾自动打印“\ r \ n”(回车换行符)。 我只是想返回光标的回车返回到行的开始。 另外, flush()是必须的,因为默认情况下, sys.stdout只是在换行符后(或缓冲区满了之后)刷新它的输出。

秘密是只打印\ r而不是\ n或\ r \ n在行和。

\ r被称为回车,它将光标移动到行首

\ n被称为换行,并将光标移动到控制台的下一行。 如果您只使用\ r覆盖先前写入的行。 所以先写下如下的一行:

 [ ] 

然后为每个打勾添加一个符号

 \r[= ] \r[== ] ... \r[==========] 

等等。 你可以使用10个字符,每个代表10%。 另外,如果你想在完成时显示一条消息,不要忘记添加足够的白色字符,以便覆盖以前写入的等号,如下所示:

 \r[done ] 

下面是我的回答,使用windows API 控制台(Windows) ,编码为C.

 /* * file: ProgressBarConsole.cpp * description: a console progress bar Demo * author: lijian <hustlijian@gmail.com> * version: 1.0 * date: 2012-12-06 */ #include <stdio.h> #include <windows.h> HANDLE hOut; CONSOLE_SCREEN_BUFFER_INFO bInfo; char charProgress[80] = {"================================================================"}; char spaceProgress = ' '; /* * show a progress in the [row] line * row start from 0 to the end */ int ProgressBar(char *task, int row, int progress) { char str[100]; int len, barLen,progressLen; COORD crStart, crCurr; GetConsoleScreenBufferInfo(hOut, &bInfo); crCurr = bInfo.dwCursorPosition; //the old position len = bInfo.dwMaximumWindowSize.X; barLen = len - 17;//minus the extra char progressLen = (int)((progress/100.0)*barLen); crStart.X = 0; crStart.Y = row; sprintf(str,"%-10s[%-.*s>%*c]%3d%%", task,progressLen,charProgress, barLen-progressLen,spaceProgress,50); #if 0 //use stdand libary SetConsoleCursorPosition(hOut, crStart); printf("%s\n", str); #else WriteConsoleOutputCharacter(hOut, str, len,crStart,NULL); #endif SetConsoleCursorPosition(hOut, crCurr); return 0; } int main(int argc, char* argv[]) { int i; hOut = GetStdHandle(STD_OUTPUT_HANDLE); GetConsoleScreenBufferInfo(hOut, &bInfo); for (i=0;i<100;i++) { ProgressBar("test", 0, i); Sleep(50); } return 0; } 

PowerShell有一个Write-Progress cmdlet,可以创build一个控制台内进度条,您可以在脚本运行时更新和修改该进度条。

这是你的问题的答案…(python)

 def disp_status(timelapse, timeout): if timelapse and timeout: percent = 100 * (float(timelapse)/float(timeout)) sys.stdout.write("progress : ["+"*"*int(percent)+" "*(100-int(percent-1))+"]"+str(percent)+" %") sys.stdout.flush() stdout.write("\r \r") 

作为格雷格回答的后续,这里是他的function的扩展版本,允许您显示多行消息; 只需传入要显示/刷新的string的列表或元组即可。

 def status(msgs): assert isinstance(msgs, (list, tuple)) sys.stdout.write(''.join(msg + '\n' for msg in msgs[:-1]) + msgs[-1] + ('\x1b[A' * (len(msgs) - 1)) + '\r') sys.stdout.flush() 

注:我只使用Linuxterminaltesting过,所以你的里程可能会在基于Windows的系统上有所不同。

如果你使用脚本语言,你可以使用“tput cup”命令来完成这个任务… PS这是一个Linux / Unix的东西,据我所知…