Как оживить командную строку?
Я всегда задавался вопросом, как люди обновляют предыдущую строку в командной строке. хорошим примером этого является использование команды wget в Linux. Он создает панель загрузки ASCII, которая выглядит следующим образом:
[====== > ] 37%
и, конечно, панель загрузки перемещается и процент изменяется, но он не создает новую строку. Я не могу понять, как это сделать. Может ли кто-нибудь указать мне в правильном направлении?
Ответы
Ответ 1
Есть два способа, которыми я знаю это:
- Используйте escape-символ возврата ('\ b') для стирания строки
- Используйте пакет
curses
, если для вашего языка программирования есть привязки для него.
И Google обнаружил ANSI Escape Codes, которые выглядят как хороший способ. Для справки, вот в С++ функция:
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.
}
Ответ 2
Один из способов сделать это - многократно обновлять строку текста с текущим прогрессом. Например:
def status(percent):
sys.stdout.write("%3d%%\r" % percent)
sys.stdout.flush()
Обратите внимание, что я использовал sys.stdout.write
вместо print
(это Python), потому что print
автоматически печатает "\ r\n" (возврат каретки new-line) в конце каждой строки. Мне просто нужен возврат каретки, который возвращает курсор к началу строки. Кроме того, flush()
необходим, потому что по умолчанию sys.stdout
только очищает свой вывод после новой строки (или после заполнения буфера).
Ответ 3
Секрет состоит в том, чтобы печатать только \r вместо\n или \r\n в строке и.
\ r называется возвратом каретки, и он перемещает курсор в начале строки
\n называется передачей строки и перемещает курсор на следующую строку
В консоли. Если вы используете только \r, вы перезаписываете ранее написанную строку.
Поэтому сначала напишите строку, как показано ниже:
[ ]
затем добавьте знак для каждого тика
\r[= ]
\r[== ]
...
\r[==========]
и т.д.
Вы можете использовать 10 символов, каждый из которых составляет 10%.
Кроме того, если вы хотите отобразить сообщение по завершении, не забудьте также добавить достаточно белых символов, чтобы вы перезаписали ранее написанные равные знаки, например:
\r[done ]
Ответ 4
ниже мой ответ, используйте API окон Консоли (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;
}
Ответ 5
В PowerShell есть командлет Write-Progress, который создает панель выполнения в консоли, которую вы можете обновлять и изменять по мере запуска script.
Ответ 6
Вот ответ на ваш вопрос... (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")
Ответ 7
В соответствии с Greg 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.
Ответ 8
Если вы используете скриптовый язык, вы можете использовать команду "tput cup", чтобы это сделать...
Постскриптум Это только Linux/Unix, насколько я знаю...