따라서 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
문자열에 개행 문자를 자동으로 추가하는 대신 --carriage 반환 문자를 사용하여 커서를 현재 줄의 시작 부분으로 보냅니다 . 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;
}