터미널 시퀀스로 기존 라인을 덮어쓰는 방법

터미널 시퀀스로 기존 라인을 덮어쓰는 방법

따라서 wget웹페이지를 열면 파일이 얼마나 다운로드되었는지 나타내는 상태 표시줄이 표시됩니다. 다음과 같습니다.

25%[=============>______________________________________] 25,000 100.0K/s (밑줄은 공백입니다. 거기에 두 개 이상의 연속된 공백을 넣는 방법을 알 수 없었습니다)

그러나 stdout에 다른 줄을 작성하고 다른 진행률 표시줄을 추가하는 대신 다음과 같이 업데이트합니다.

50%[===========================>________________________] 50,000 100.0K/s

그리고 wget이것만이 유일한 예는 아닙니다. 예를 들어, 무언가를 파이프한 less후 종료하면 이전에 실행한 명령의 결과와 함께 원래 프롬프트가 그대로 유지됩니다. 마치 당신이 떠나지 않은 것 같습니다.

그래서 제 질문은 이것이 무엇인지, 어떻게 구현하는지, 한 번에 한 줄씩만 작동하는지, C에서 사용할 수 있는지입니다.

답변1

우선 귀하의 질문은 bash와 관련이 없지만 터미널과 관련이 있습니다. 터미널은 프로그램의 텍스트를 표시하기 위해 응답하고 있으며 bash 자체는 프로그램이 시작된 후에는 프로그램을 제어할 수 없습니다.

터미널은 색상, 글꼴, 커서 위치 등을 제어하는 ​​제어 시퀀스를 제공합니다. 표준화된 터미널 시퀀스 목록을 보려면 다음을 참조하세요. http://www.termsys.demon.co.uk/vtansi.htm예를 들어

  • 줄의 시작 부분에 커서를 놓습니다.
  • 나중에 줄을 삭제
  • 새로운 줄을 써라

진행률 표시줄을 생성합니다.

고급 터미널 이스케이프 시퀀스는 일반적으로 터미널에 따라 다릅니다. 예를 들어 Eterm 또는 xterm에서만 작동합니다.저주를 받다- 이스케이프 시퀀스를 사용할 필요가 없도록 터미널과 대화형 프로그램을 만드는 프로그래밍 라이브러리입니다.

터미널 시퀀스로 기존 라인을 덮어쓰는 방법

echo long text
sleep 1
printf "\033[1A"  # move cursor one line up
printf "\033[K"   # delete till end of line
echo foo

터미널 시퀀스 없이 기존 라인을 덮어쓰는 방법

한 가지 간단한 해결책은 끝에 줄바꿈을 쓰지 않고 캐리지 리턴을 쓰는 것입니다. 이는 기본적으로 커서를 줄의 시작 부분으로 재설정합니다. 예:

echo -n first 
sleep 1 
echo -ne "\rsecond"
echo

또는 캐리지 \r리턴을 사용하면 커서가 줄의 시작 부분에 놓이고 줄의 내용을 덮어쓸 수 있습니다.

less또는 같은 버퍼 간 전환vi

의 동작은 less또한 고급 터미널 기능인 대체 화면으로 인해 발생합니다.

VT102 모드에는 창의 표시 영역과 동일한 크기인 대체 화면 버퍼를 활성화 및 비활성화하는 이스케이프 시퀀스가 ​​있습니다. 활성화되면 현재 화면이 저장되고 대체 화면으로 교체됩니다. 창 상단에서 스크롤된 줄은 일반 화면이 복원될 때까지 저장되지 않습니다. xterm의 termcap(5) 항목을 사용하면 시각적 편집기 vi(1)가 편집을 위해 대체 화면으로 전환하고 종료 시 화면을 복원할 수 있습니다. 팝업 메뉴 항목을 사용하면 잘라내기와 붙여넣기를 위한 일반 화면과 대체 화면 사이를 쉽게 전환할 수 있습니다.

http://rosettacode.org/wiki/Terminal_control/Preserve_screen다음을 통해 직접 수행하는 방법에 대한 몇 가지 예를 나열합니다.입력또는 일부 이스케이프 시퀀스를 통해.

답변2

echo문자열에 개행 문자를 자동으로 추가하는 대신 printf "%s\r" whatever-- 캐리지 리턴을 사용하면 커서를 현재 줄의 시작 부분으로 보냅니다. 예:

seq 1 15 | while read num; do printf "%2d\r" $num; sleep 1; done; echo ""

답변3

나는 또한 이 주제를 발견한 사람들에게 한 번 보도록 권하고 싶습니다.Bash 프롬프트 HOWTO - 커서 이동.

예:

- Position the Cursor:
  \033[<L>;<C>H
     Or
  \033[<L>;<C>f
  puts the cursor at line L and column C.
- Move the cursor up N lines:
  \033[<N>A
- Move the cursor down N lines:
  \033[<N>B
- Move the cursor forward N columns:
  \033[<N>C
- Move the cursor backward N columns:
  \033[<N>D

- Clear the screen, move to (0,0):
  \033[2J
- Erase to end of line:
  \033[K

- Save cursor position:
  \033[s
- Restore cursor position:
  \033[u

C의 몇 가지 예:

void saveCursorPosition() {
  printf("\033[s");
}

void restoreCursorPosition() {
  printf("\033[u");
}

void lineUP(short int times) {
  printf("\033[%iA", times);
}

void lineDown(short int times) {
  printf("\033[%iB", times);
}

프로그램 샘플:

#include <stdio.h>
#include <unistd.h>

void saveCursorPosition() {
  printf("\033[s");
}

void restoreCursorPosition() {
  printf("\033[u");
}

void lineUP(short int times) {
  printf("\033[%iA", times);
}

void moveCursorBackwards(short int times) {
  printf("\033[%iD", times);
}

void printMainText() {

  printf("\n ╔═══════════════════════════════╗");
  printf("\n ║                               ║");
  printf("\n ║ Progress Bar                  ║");
  printf("\n ║                               ║");
  printf("\n ║ []                            ║");
  printf("\n ║                               ║");
  printf("\n ║ Press Ctrl+C to close         ║");
  printf("\n ║                               ║");
  printf("\n ╚═══════════════════════════════╝\n");

}

int main(int argc, char **argv) {

  printMainText();

  for (int progress=0; progress <= 10; progress++) {

    saveCursorPosition();
    lineUP(5);

    printf("\r ║     [");
    fflush(stdout);

    for (int i=0; i<progress; i++) {
      printf("=>]");
      fflush(stdout);
      moveCursorBackwards(2);
    }

    moveCursorBackwards(progress + 5);

    printf("%i%%", progress * 10);
    fflush(stdout);

    restoreCursorPosition();

    sleep(1);

  }

  return 0;

}

관련 정보