Как оживить командную строку? - PullRequest
78 голосов
/ 13 сентября 2008

Мне всегда было интересно, как люди обновляют предыдущую строку в командной строке. отличный пример этого - использование команды wget в linux. Он создает панель загрузки ASCII, которая выглядит следующим образом:

[======>] 37%

и, конечно, полоса загрузки сдвигается и процент изменяется, но она не создает новую строку. Я не могу понять, как это сделать. Может ли кто-нибудь указать мне правильное направление?

Ответы [ 8 ]

56 голосов
/ 13 сентября 2008

Один из способов сделать это - многократно обновлять строку текста с текущим прогрессом. Например:

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

Обратите внимание, что я использовал sys.stdout.write вместо print (это Python), потому что print автоматически печатает "\ r \ n" (перевод строки при возврате каретки) в конце каждой строки. Я просто хочу возврат каретки, который возвращает курсор в начало строки. Кроме того, flush() необходим, потому что по умолчанию sys.stdout сбрасывает свой вывод только после новой строки (или после того, как его буфер заполнен).

42 голосов
/ 13 сентября 2008

Есть два способа сделать это:

  • Используйте символ возврата на клавишу возврата ('\ b'), чтобы стереть вашу строку
  • Используйте пакет curses, если для выбранного языка программирования есть привязки.

А 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.
}
16 голосов
/ 06 октября 2014

Секрет заключается в том, чтобы печатать только \ r вместо \ n или \ r \ n в строке и.

\ r называется возвратом каретки и перемещает курсор в начало строки

\ n называется переводом строки и перемещает курсор на следующую строку В консоли. Если вы используете только \ r, вы перезаписываете ранее написанную строку. Поэтому сначала напишите строку, подобную следующей:

[          ]

затем добавьте знак для каждого тика

\r[=         ]

\r[==        ]

...

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

и так далее. Вы можете использовать 10 символов, каждый из которых представляет 10%. Кроме того, если вы хотите отобразить сообщение, когда закончите, не забудьте также добавить достаточно белых символов, чтобы перезаписать ранее написанные знаки равенства, например:

\r[done      ]
4 голосов
/ 06 декабря 2012

ниже мой ответ, используйте 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;
}
3 голосов
/ 04 июля 2012

Вот ответ на ваш вопрос ... (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")
3 голосов
/ 13 сентября 2008

В PowerShell есть командлет Write-Progress, который создает консольную индикатор выполнения, который можно обновлять и изменять при запуске сценария.

2 голосов
/ 24 июня 2012

В качестве ответа до Ответ Грега , вот расширенная версия его функции, которая позволяет отображать многострочные сообщения; просто передайте список или кортеж строк, которые вы хотите отобразить / обновить.

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 голосов
/ 24 октября 2009

Если вы используете язык сценариев, вы можете использовать команду "tput cup", чтобы сделать это ... Постскриптум Насколько я знаю, это вещь для Linux / Unix ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...