Evitar que o texto / tela pisque ao limpar

8

Meu script fazendo algo como:

while :;
   clear

   do_a_lot_of_output_here

   sleep 1
done

Há alguma opção para impedir que a tela pisque quando eu estiver fazendo a limpeza e a saída? Eu quero fazer como no comando watch (mas está escrito em C ). Algum conselho?

clear | hexdump -C

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

PS. Estou usando apenas bash .

    
por ravnur 29.06.2013 / 22:47

4 respostas

7

O piscar ocorre porque o script limpa a tela inteira. Se pintar o texto existente e apagar apenas quando necessário, não haverá trepidação.

Aqui está um exemplo:

#!/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

Ele faz isso:

  • imprime a saída do comando especificado que caberá na tela (sem quebra automática ou rolagem)
  • escreve sobre linhas existentes, limpando a parte de cada linha que não é sobrescrita
  • usa o recurso ed do seu terminal para imprimir do local atual até o final da tela.

Se você quisesse manipular uma tela redimensionável, poderia mover as atribuições para ROWS e COLS dentro do loop externo, por exemplo,

#!/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

porque tput pede o tamanho de tela atual do sistema.

Leitura adicional:

  • terminfo - base de dados de capacidade do terminal
  • tput , reset - inicializa um terminal ou consulta o banco de dados terminfo
por 09.04.2016 / 21:22
6

Uma forma de ajudar a evitar a intermitência é obter toda a saída antes de limpar a tela para que haja um tempo mínimo entre a limpeza e o redesenho. Isso é semelhante ao conceito de buffer duplo:

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

Isso não elimina completamente o flicker, mas acontece com uma frequência significativamente menor na minha experiência.

    
por 23.04.2014 / 18:25
4

O piscar é um resultado inevitável de limpar a tela a cada volta do loop. Você pode mover o cursor para o topo da tela e substituir partes de sua saída antiga.

# 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 '3[;H' 
    do_a_lot_of_output_here
    sleep 1
done

Esse script deixará artefatos se a sua saída encolher. Também não é muito provável que seja portátil. Eu só testei com urxvt, xterm e st.

    
por 29.06.2013 / 23:15
1

Como extensão da resposta de Cristian, fiz a seguinte função bash que funciona se a janela do console for menor que a saída do comando:

function watcher()
{
    lines=$(tput lines)
    while true; do
        output="$($@ | head -n $lines)"
        clear
        echo -e "$output"
        sleep 2
    done
}

Isso permite que você passe qualquer comando para o observador. Se você estiver usando o git, use git config --global color.status always e depois:

watcher git status

Exibe uma saída de status git sempre atualizada.

    
por 07.10.2015 / 21:10

Tags