2008-09-13 3 views
74

私は、人々がコマンドラインで前の行をどのように更新するのか、常に疑問を抱きました。これの素晴らしい例は、linuxでwgetコマンドを使用する場合です。コマンドラインをアニメーション化する方法は?

[======>                                        ] 37%:それはこのようになります種類のASCIIローディングバーを作成します

もちろん、loa ding barの動きとパーセント変化、しかしそれは新しい行を作ることはありません。私はこれを行う方法を理解することはできません。誰かが私を正しい方向に向けることができますか?

答えて

42

これを行うには、私の知っている2つの方法があります。

  • は選択のあなたのプログラミング言語ならば、cursesパッケージを使用
  • あなたのラインを消去するには、バックスペースエスケープ文字(「\ B」)を使用それのための拘束力を持っています。

そして、GoogleがANSI Escape Codesを明らかにしました。これは良い方法と思われます。参考までに、ここではこれを行うためのC++の関数を示します:

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. 
} 
+7

彼はWin32コンソールアプリケーションを実行していると仮定すると、(ありませんDOS)を使用している場合、ANSIのエスケープコードはまったく動作しません。あなたがリンクしているウィキペディアの記事に述べられているように。 –

+0

WindowsでANSIエスケープシーケンスを使用する場合、Ansiconを使用することがあります。 https://github.com/adoxa/ansicon –

56

これを行う1つの方法は、テキスト行を現在の進行状況で繰り返し更新することです。例えば:私はsys.stdout.write代わりにprintを使用

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

注意(これは、Pythonである)print自動的にプリントため、「\ R \ n」(改行をキャリッジリターン)各ラインの終わりに。私はちょうどラインの開始にカーソルを返すキャリッジリターンが必要です。また、デフォルトではsys.stdoutは改行後(またはそのバッファがいっぱいになった後)にのみ出力をフラッシュするため、flush()が必要です。

+0

そして 'c'とprintf、 '\ r'と同じです。 –

+0

'' flush() 'の後に正確に" flush "されるのは何ですか?ちょうど興味があります... – Nearoo

+0

@ Nearoo通常、stdoutは改行(\ n)が書き込まれるまでその出力をバッファします。フラッシュすると、部分行がすぐに表示されます。 –

3

PowerShellには、スクリプトが実行されるときに更新および変更できるコンソール内プログレスバーを作成するWrite-Progressコマンドレットがあります。

0

スクリプト言語を使用している場合、これを行うには「tput cup」コマンドを使用できます。 P.S.これは私が知っている限り、Linux/Unixのことです。

2

以下は、Greg's answerのフォローアップで、複数行のメッセージを表示できる彼の機能の拡張バージョンです。表示/更新したい文字列のリストまたはタプルを渡します。

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() 

注:これはLinux端末を使用してテストされているため、Windowsベースのシステムではマイレージが異なる場合があります。ここで

+0

Windows(7sp1x64):動作しません。 – n611x007

+0

@naxa Gregの答えは(上の)あなたのために働きますか?改行文字に問題がある可能性が最も高いです。 '\ n'を '\ r \ n'に置き換えてください。 – Blaker

+0

グレッグは動いているので、1行で動作しますが、私は複数行のメッセージの更新をしようとしました。 :)あなたのスクリプトで '\ n'を' \ r \ n'に置き換えましたが、まだそれをWindows上で動かすことができませんでしたか?私は '←[A←[A'いくつかのメッセージの後に、' '\ x1b [A''シーケンスが' cmd.exe'で何をするべきかを疑っています。 – n611x007

3

は、あなたの質問に対する答えは...(パイソン)以下

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") 
4

は、Windows API Consoles(Windows)を使用し、私の答えは、Cのコーディング

/* 
* file: ProgressBarConsole.cpp 
* description: a console progress bar Demo 
* author: lijian <[email protected]> 
* 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; 
} 
+0

'bInfo'はどこに定義されていますか? –

13

秘密は、行と行の\ nまたは\ r \ nの代わりに\ rのみを印刷することです。 R \

は、キャリッジリターンと呼ばれ、

\ nは改行と呼ばれている行の先頭にカーソルを移動し、それがコンソールの次の行 にカーソルを移動させます。 \ rだけを使用すると、前に書き込まれた行が上書きされます。 だから最初に次のような行を記述します。

[   ] 

その後、各目盛り

\r[=   ] 

\r[==  ] 

... 

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

などの看板を追加します。 10文字を使用できます。それぞれ10%を表します。 あなたが終了したときにメッセージを表示したい場合にも、あなたがそうのような以前に書かれた等号を上書きするようにも十分に白い文字を追加することを忘れないでください:

\r[done  ] 
+1

これは完全に機能しました。私の意見ではそれはずっと簡単です。 – Erutan409

関連する問題