삭제 시 텍스트/화면 깜박임 방지

삭제 시 텍스트/화면 깜박임 방지

내 스크립트는 비슷한 작업을 수행합니다.

while :;
   clear

   do_a_lot_of_output_here

   sleep 1
done

클리어 및 출력시 화면이 깜박이는 현상을 방지할 수 있는 옵션이 있나요? 나는 watch명령에서처럼 이것을 하고 싶다 (그러나 그것은 에 쓰여 있다 C). 어떤 제안이 있으십니까?

clear | hexdump -C

00000000  1b 5b 48 1b 5b 32 4a                              |.[H.[2J|
00000007

PS. 저는 bash.

답변1

깜박임을 방지하는 한 가지 방법은 화면을 지우고 다시 그리는 사이의 시간을 최소화하도록 화면을 지우기 전에 모든 출력을 얻는 것입니다. 이는 이중 버퍼링의 개념과 유사합니다.

while :; do
   output=$(do_a_lot_of_output_here)
   clear
   echo "$output"
   sleep 1
done

이렇게 하면 깜박임이 완전히 제거되지는 않지만 내 경험상 깜박임 발생 빈도는 상당히 줄어듭니다.

답변2

깜박임은 스크립트가 전체 화면을 지우기 때문에 발생합니다. 기존 텍스트를 덮어쓰고 필요할 때만 지우면 깜박임이 발생하지 않습니다.

예는 다음과 같습니다.

#!/bin/sh
watchit() {
    HOME=$(tput cup 0 0)
    ED=$(tput ed)
    EL=$(tput el)
    ROWS=$(tput lines)
    COLS=$(tput cols)
    printf '%s%s' "$HOME" "$ED"
    while true
    do
        CMD="$@"
        ${SHELL:=sh} -c "$CMD" | head -n $ROWS | while IFS= read LINE; do
            printf '%-*.*s%s\n' $COLS $COLS "$LINE" "$EL"
        done
        printf '%s%s' "$ED" "$HOME"
        sleep 1
    done
}

watchit top -b -n 1

이는 다음을 수행합니다.

  • 주어진 명령의 출력을 화면에 맞게 인쇄합니다(줄바꿈이나 스크롤 없이).
  • 기존 행을 덮어쓰고 각 행에서 발견되지 않은 부분을 지웁니다.
  • 터미널의 기능을 사용하여 ed현재 위치부터 화면 끝까지 인쇄합니다.

크기 조정 가능한 화면을 처리하려면 할당을 외부 루프 내부로 이동할 수 있습니다 ROWS.COLS

#!/bin/sh
watchit() {
    HOME=$(tput cup 0 0)
    ED=$(tput ed)
    EL=$(tput el)
    printf '%s%s' "$HOME" "$ED"
    while true
    do
        ROWS=$(tput lines)
        COLS=$(tput cols)
        CMD="$@"
        ${SHELL:=sh} -c "$CMD" | head -n $ROWS | while IFS= read LINE; do
            printf '%-*.*s%s\n' $COLS $COLS "$LINE" "$EL"
        done
        printf '%s%s' "$ED" "$HOME"
        sleep 1
    done
}

watchit top -b -n 1

왜냐하면 tput시스템에서 현재 화면 크기를 가져와야 하기 때문입니다.

추가 자료:

답변3

깜박임은 화면이 순환할 때마다 화면이 지워지는 피할 수 없는 결과입니다. 커서를 화면 상단으로 이동하고 이전 출력의 일부를 덮어쓸 수 있습니다.

# You may want to do this if your code is in a script.
unhide_cursor() {
    printf '\e[?25h'
}
trap unhide_cursor EXIT

# Hide the cursor (there is probably a much better way to do this)
printf '\e[?25l'
clear 
while true ; do
    # Move the cursor to the top of the screen but don't clear the screen
    printf '\033[;H' 
    do_a_lot_of_output_here
    sleep 1
done

출력이 축소되면 이 스크립트는 아티팩트를 남깁니다. 또한 휴대성이 떨어지는 경우도 있습니다. 나는 urxvt, xterm 및 st로만 테스트했습니다.

답변4

한 줄인지 여러 줄인지에 따라 다릅니다. tput도 나쁜 선택은 아니지만 esc 코드를 사용하는 것이 더 좋습니다...

while true
do
    printf "^[[H^[[0K$do_a_lot_of_output"
    sleep 0.01
done

^[[H커서를 0,0 또는 왼쪽 상단으로 이동합니다. ^[[0K는 현재 커서 위치에서 줄 끝까지의 내용을 삭제합니다.

^[[0K현재 커서 위치에서 줄 끝까지 줄을 지우고 다음 문자열이 이전 문자열보다 짧아지면 남은 데이터가 표시되지 않기 때문에 좋습니다.

예를 들어 첫 번째 반복 동안 $do_a_lot_of_output = 20이고 두 번째 반복 동안 $do_a_lot_of_output = 5인 경우 출력은 50이 됩니다. ^[[0K가 필요한 범위만 출력하므로 포함하지 않으면 20개 중 2개가 새 5로 덮어쓰여지지만 0은 여전히 ​​잘못된 50을 제공합니다.

제 생각엔 ^[[K 도 쓸 수 있을 것 같아요

ctrl+v를 눌러 esc 코드 시퀀스를 시작한 다음 ESC를 눌러 ^[를 생성한 다음 이 경우 다른 [ + 코드 H 또는 K를 추가하세요.

당신은 그것들을 합치고 ^[[H 또는 ^[[K를 얻습니다.

Ansi 이스케이프 코드 목록: https://gist.github.com/fnky/458719343aabd01cfb17a3a4f7296797

관련 정보