developer tip

명령 줄을 애니메이션하는 방법은 무엇입니까?

copycodes 2020. 10. 10. 10:12
반응형

명령 줄을 애니메이션하는 방법은 무엇입니까?


나는 사람들이 명령 줄에서 이전 줄을 어떻게 업데이트하는지 항상 궁금해했습니다. 이에 대한 좋은 예는 Linux에서 wget 명령을 사용할 때입니다. 다음과 같은 ASCII 로딩 바를 생성합니다.

[======>] 37 %

물론 로딩 바가 움직이고 퍼센트가 변경되지만 새로운 라인을 만들지는 않습니다. 이 작업을 수행하는 방법을 알 수 없습니다. 누군가 나를 올바른 방향으로 가리킬 수 있습니까?


이 작업을 수행하는 방법에는 두 가지가 있습니다.

  • 백 스페이스 이스케이프 문자 ( '\ b')를 사용하여 줄을 지 웁니다.
  • curses선택한 프로그래밍 언어에 바인딩이있는 경우 패키지를 사용하십시오 .

그리고 구글 은 좋은 방법으로 보이는 ANSI 이스케이프 코드를 공개했습니다 . 참고로 다음은이를 수행하는 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.
}

이를 수행하는 한 가지 방법은 현재 진행 상황으로 텍스트 줄을 반복적으로 업데이트하는 것입니다. 예를 들면 :

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

각 줄 끝에 "\ r \ n"(carriage-return new-line)을 자동으로 인쇄 하기 때문에 (이것은 Python) sys.stdout.write대신 사용 했습니다 . 커서를 줄의 시작 부분으로 되 돌리는 캐리지 리턴을 원합니다. 또한,은 기본적으로 있기 때문에 필요한 경우에만 줄 바꿈 후 (또는 버퍼가 가득 차면 후)의 출력을 플러시합니다.printprintflush()sys.stdout


비밀은 줄 및 줄에 \ n 또는 \ r \ n 대신 \ r 만 인쇄하는 것입니다.

\ r 캐리지 리턴이라고하며 줄의 시작 부분에서 커서를 이동합니다.

\ n은 줄 바꿈이라고하며 콘솔에서 커서를 다음 줄로 이동합니다. \ r 만 사용하면 이전에 작성된 줄을 덮어 씁니다. 따라서 먼저 다음과 같은 줄을 작성하십시오.

[          ]

그런 다음 각 진드기에 대한 기호를 추가하십시오

\r[=         ]

\r[==        ]

...

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

등등. 각각 10 %를 나타내는 10 개의 문자를 사용할 수 있습니다. 또한 완료되었을 때 메시지를 표시하려면 이전에 작성된 등호를 다음과 같이 덮어 쓸 수 있도록 충분한 흰색 문자를 추가하는 것을 잊지 마십시오.

\r[done      ]

아래는 내 대답입니다 .Windows API Consoles (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이 있습니다.


귀하의 질문에 대한 답변은 다음과 같습니다.

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

Greg의 대답에 대한 후속으로 , 여기에 여러 줄 메시지를 표시 할 수있는 그의 기능의 확장 버전이 있습니다. 표시 / 새로 고침하려는 문자열의 목록 또는 튜플을 전달하기 만하면됩니다.

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

Note: I have only tested this using a linux terminal, so your mileage may vary on Windows-based systems.


If your using a scripting language you could use the "tput cup" command to get this done... P.S. This is a Linux/Unix thing only as far as I know...

참고URL : https://stackoverflow.com/questions/60221/how-to-animate-the-command-line

반응형