programing

bash를 사용하여 단말기의 마지막 줄을 삭제하고 교체하는 방법은 무엇입니까?

skycolor 2023. 5. 27. 09:59
반응형

bash를 사용하여 단말기의 마지막 줄을 삭제하고 교체하는 방법은 무엇입니까?

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

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

$ Elapsed time 5 seconds

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

$ Elapsed time 15 seconds

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

$ echo -e "abcdefghijklmnopqrstuvwxyz\r0123456789"
0123456789klmnopqrstuvwxyz

새 텍스트의 줄을 실제로 지우려면 다음을 추가할 수 있습니다.\033[K그 후에\r:

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

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

캐리지 리턴을 \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

회선 길이가 단자 폭을 초과하지 않는 한 Derek Beit의 대답은 잘 작동합니다.그렇지 않은 경우 다음 코드는 정크 출력을 방지합니다.

행이 처음으로 쓰여지기 전에, 을 하라.

tput sc

현재 커서 위치를 저장합니다.이제 당신이 당신의 라인을 인쇄하고 싶을 때마다,

tput rc
tput ed
echo "your stuff here"

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

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"

진행률 출력이 다중 줄이거나 스크립트가 이미 새 줄 문자를 인쇄한 경우 다음과 같은 방법으로 줄을 점프할 수 있습니다.

printf "\033[5A"

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

그게 안 되면 당신은 시도할 수 있습니다.printf "\e[5A"또는echo -e "\033[5A"같은 효과가 있어야 합니다.

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

캐리지 리턴 문자를 사용합니다.

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

이전 줄을 지우려면 다음과 같이 하면 됩니다.

printf '\033[1A\033[K'

여러 줄의 경우 루프에서 사용합니다.

for i in {1..10}; do
    printf '\033[1A\033[K'
done

이렇게 하면 마지막 10줄이 지워집니다.

캐리지 리턴을 배치하여 이를 달성할 수 있습니다.\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

에서 백슬래시를 사용하는 대신echos, 사용할 수 있습니다.tput이를 단순화하기 위해 다음과 같은 함수를 만들 수 있습니다.

#!/bin/bash

function consoleoneline {
    # Start process and save all outputs in a temporary directory
    tput sc # save current cursor in console
    local PIPE_DIRECTORY=$(mktemp -d)
    trap "rm -rf '$PIPE_DIRECTORY'" EXIT

    mkfifo "$PIPE_DIRECTORY/stdout"
    mkfifo "$PIPE_DIRECTORY/stderr"

    "$@" >"$PIPE_DIRECTORY/stdout" 2>"$PIPE_DIRECTORY/stderr" &
    local CHILD_PID=$!

    # Replace all outputs with a leading "›"
    # `tput` allows to reset the cursor to the previous line
    sed "s/^/`tput rc;tput el`› /" "$PIPE_DIRECTORY/stdout" &
    sed "s/^/`tput rc;tput el`› /" "$PIPE_DIRECTORY/stderr" >&2 &

    # Wait command has exited, remove temporary directory and reset cursor
    wait "$CHILD_PID"
    rm -rf "$PIPE_DIRECTORY"
    tput ed
}

consoleoneline bash -c 'echo 1 && sleep 1 && echo 2 && sleep 1 && echo 3'

언급URL : https://stackoverflow.com/questions/2388090/how-to-delete-and-replace-last-line-in-the-terminal-using-bash

반응형