bash를 사용하여 터미널의 마지막 줄을 삭제하고 바꾸는 방법은 무엇입니까?


99

bash에서 경과 된 초를 표시하는 진행률 표시 줄을 구현하고 싶습니다. 이를 위해 화면에 표시된 마지막 줄을 지워야합니다 ( "clear"명령은 모든 화면을 지우지 만 진행 표시 줄의 줄만 지우고 새 정보로 교체해야 함).

최종 결과는 다음과 같습니다.

$ Elapsed time 5 seconds

그런 다음 10 초 후에이 문장 (화면의 같은 위치에 있음)을 다음과 같이 바꾸고 싶습니다.

$ Elapsed time 15 seconds

답변:


117

\ r로 캐리지 리턴을 에코

seq 1 1000000 | while read i; do echo -en "\r$i"; done

맨 에코에서 :

-n     do not output the trailing newline
-e     enable interpretation of backslash escapes

\r     carriage return

19
for i in {1..100000}; do echo -en "\r$i"; done서열 호출 :-) 피하기 위해
더글러스 Leeder 씨

이것은 내가 필요한 것을 정확히 수행합니다, 감사합니다! 그리고 seq 명령을 사용하면 실제로 터미널이 고정됩니다. :-)
Debugger

11
"for i in $ (...)"또는 "for i in {1..N}"과 같은 것을 사용하면 반복하기 전에 모든 요소를 ​​생성하게됩니다. 이는 대규모 입력에 대해 매우 비효율적입니다. 파이프를 이용할 수 있습니다 : "seq 1 100000 | while read i; do ..."또는 bash c 스타일 for 루프를 사용할 수 있습니다. "for ((i = 0 ;; i ++)); do ..."
tokland 2010 년

Douglas와 tokland에게 감사드립니다. 시퀀스 제작이 제가 tokland의 더 효율적인 파이프로 변경 한 질문의 직접적인 부분은 아니었지만
Ken

1
매트릭스 프린터가 용지를 완전히 엉망으로 만듭니다. 더 이상 존재하지 않는 동일한 용지에 점이 계속 걸리게됩니다.이 프로그램은 얼마나 오래 실행됩니까?
Rob

185

캐리지 리턴 자체는 커서를 줄의 시작 부분으로 만 이동합니다. 출력의 각 새 줄이 적어도 이전 줄보다 길면 괜찮지 만 새 줄이 더 짧으면 이전 줄을 완전히 덮어 쓰지 않습니다. 예 :

$ echo -e "abcdefghijklmnopqrstuvwxyz\r0123456789"
0123456789klmnopqrstuvwxyz

실제로 새 텍스트에 대한 행을 삭제하려면, 당신은 추가 할 수 있습니다 \033[K애프터 \r:

$ echo -e "abcdefghijklmnopqrstuvwxyz\r\033[K0123456789"
0123456789

http://en.wikipedia.org/wiki/ANSI_escape_code


3
이것은 내 환경에서 정말 잘 작동합니다. 호환성에 대한 지식이 있습니까?
Alexander Olsson 2011

21
배쉬에서 최소한으로 단축 할 수있는 \e[K대신에 \033[K.
Dave James Miller

좋은 대답입니다! 루비의 풋을 사용하여 완벽하게 작동합니다. 이제 내 툴킷의 일부입니다.
phatmann

@The Pixel 개발자 : 개선 해주셔서 감사합니다.하지만 수정이 잘못되었습니다. 커서를 줄의 시작 부분으로 이동하려면 먼저 반환해야합니다. 그런 다음 강제 종료는 해당 커서 위치에서 끝까지 모든 것을 지우고 전체 줄을 비워 둡니다. Ken의 대답과 유사하게 각 새 줄의 시작 부분에 배치하여 빈 줄에 작성됩니다.
Derek Veit

1
기록을 위해 분명히 훨씬 더 간단 하지만 이전에 \033[Gio \r를 수행 할 수도 있습니다 . 또한 invisible-island.net/xterm/ctlseqs/ctlseqs.html 은 Wikipedia보다 자세한 내용을 제공하며 xterm 개발자가 제공합니다. \033[K\r
jamadagni

19

Derek Veit의 대답은 라인 길이가 터미널 너비를 초과하지 않는 한 잘 작동합니다. 그렇지 않은 경우 다음 코드는 정크 출력을 방지합니다.

줄이 처음으로 작성되기 전에

tput sc

현재 커서 위치를 저장합니다. 이제 라인을 인쇄 할 때마다

tput rc
tput ed
echo "your stuff here"

먼저 저장된 커서 위치로 돌아간 다음 커서에서 아래쪽으로 화면을 지우고 마지막으로 출력을 씁니다.


이상하다, 이것은 터미네이터에서 아무것도하지 않는다. 호환성 제한이 있는지 알고 있습니까?
Jamie Pate 2014

1
Cygwin에 대한 참고 사항 : "tput"을 사용하려면 "ncurses"패키지를 설치해야합니다.
Jack Miller

흠 ... 출력에 한 줄 이상이 있으면 작동하지 않는 것 같습니다. 이 작동하지 않습니다tput sc # save cursor echo '' > sessions.log.json while [ 1 ]; do curl 'http://localhost/jolokia/read/*:type=Manager,*/activeSessions,maxActiveSessions' >> sessions.log.json echo '' >> sessions.log.json cat sessions.log.json | jq '.' tput rc;tput el # rc = restore cursor, el = erase to end of line sleep 1 done
NUX

@Nux tput ed대신 tput el. @Um의 예제가 사용되었습니다 ed(아마 당신이 주석을 달고 나서 고쳤을 것입니다).
studgeek

참고로, 여기 tput을 명령의 목록입니다 tput을 가진 색상 및 커서 이동
studgeek

12

\ 033 방법이 작동하지 않았습니다. \ r 메서드는 작동하지만 실제로는 아무것도 지우지 않고 커서를 줄의 시작 부분에 놓습니다. 따라서 새 문자열이 이전 문자열보다 짧으면 줄 끝에 남은 텍스트를 볼 수 있습니다. 결국 tput은 가장 좋은 방법이었습니다. 커서 외에도 다른 용도로 사용되며 많은 Linux 및 BSD 배포판에 사전 설치되어 있으므로 대부분의 bash 사용자가 사용할 수 있습니다.

#/bin/bash
tput sc # save cursor
printf "Something that I made up for this string"
sleep 1
tput rc;tput el # rc = restore cursor, el = erase to end of line
printf "Another message for testing"
sleep 1
tput rc;tput el
printf "Yet another one"
sleep 1
tput rc;tput el

다음은 재생할 작은 카운트 다운 스크립트입니다.

#!/bin/bash
timeout () {
    tput sc
    time=$1; while [ $time -ge 0 ]; do
        tput rc; tput el
        printf "$2" $time
        ((time--))
        sleep 1
    done
    tput rc; tput ed;
}

timeout 10 "Self-destructing in %s"

그것은 실제로 전체 라인을
정리합니다

5

진행률 출력이 여러 줄이거 나 스크립트가 이미 새 줄 문자를 인쇄 한 경우 다음과 같이 줄을 이동할 수 있습니다.

printf "\033[5A"

그러면 커서가 5 줄 위로 점프합니다. 그런 다음 필요한 것을 덮어 쓸 수 있습니다.

그 작동하지 않을 경우 당신은 시도 할 수 printf "\e[5A"또는 echo -e "\033[5A"같은 효과를 가지고 있어야한다.

기본적으로 이스케이프 시퀀스 를 사용하면 화면의 거의 모든 것을 제어 할 수 있습니다.


이것에 상응하는 휴대용은이며 tput cuu 5, 여기서 5는 행의 수입니다 ( cuu위로 cud이동, 아래로 이동).
Maëlan

4

캐리지 리턴 문자 사용 :

echo -e "Foo\rBar" # Will print "Bar"

이 대답이 가장 간단한 방법입니다. 당신은 사용하여 동일한 효과를 얻을 수 있습니다 : printf와 "푸 \ rBar"
lee8oi

1

캐리지 리턴을 배치하여 달성 할 수 있습니다 \r.

한 줄의 코드로 printf

for i in {10..1}; do printf "Counting down: $i\r" && sleep 1; done

또는 echo -ne

for i in {10..1}; do echo -ne "Counting down: $i\r" && sleep 1; done
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.