Evite que o texto / tela pisque ao limpar


11

Meu script fazendo algo como:

while :;
   clear

   do_a_lot_of_output_here

   sleep 1
done

Existem opções para evitar que a tela pisque quando estou limpando e saindo? Eu quero fazê-lo como no watchcomando (mas está escrito em C). Algum conselho?

clear | hexdump -C

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

PS. Eu estou usando bashapenas.


Você pode adicionar a saída do seu clear | hexdump -C?
ott--

Eu expandi a pergunta.
ravnur

Encontrei outra solução em stackoverflow.com/questions/5367068/… - o echo -en "\ec"flash também?
ott--

Eu encontrei esse também. As duas variantes da resposta também piscam.
ravnur

Eu tive sucesso com esta ferramenta: excess.org/article/2009/07/watch1-bash-unicode
Raine

Respostas:


8

O piscar ocorre porque o script limpa a tela inteira. Se pintar sobre o texto existente e limpar apenas quando necessário, não haverá tremulaçã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

Faz o seguinte:

  • imprime a saída do comando fornecido que se ajustará à tela (sem quebra ou rolagem)
  • escreve sobre as linhas existentes, limpando a parte de cada linha que não é substituída
  • utiliza a edcapacidade do seu terminal para imprimir da localização atual até o final da tela.

Se você quiser manipular uma tela redimensionável, poderá mover as atribuições para ROWSe COLSdentro 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 tputpede o tamanho da tela atual do sistema.

Leitura adicional:


1
Para quem usa #!/bin/bashe deseja usar watchitincorporado em um pequeno script independente com algumas funções, você pode fazê-lo export -f function_name; watchit function_name.
aggregate1166877

Isso funcionou perfeitamente para mim, exceto pelo fato de eu ter problemas engraçados na parte superior da tela, onde as coisas mudavam e se tornavam problemáticas por trechos mais longos de texto (qualquer coisa que fosse reduzida head). Parece que o problema é um erro pontual (pelo menos na minha configuração - sessão ssh em painéis divididos, iTerm2) ao calcular o número de linhas. ROWS=`expr $(tput lines) - 1`abordou isso perfeitamente.
ohruunuruus

Isso é maravilhoso, muito obrigado @ thomas-dickey.
mbarkhau

9

Uma maneira de ajudar a evitar piscar é obter toda a saída antes de limpar a tela, para que haja um período mínimo de tempo entre limpá-la e redesenhá-la. 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.


Buffer duplo, assim como em qualquer outra situação, cofres do dia :-)
Ikke

Funcionou como um encanto. Sem cintilação :)
Lars Juel Jensen

1
A cintilação restante pode ser eliminada incluindo-a clearno buffer, ou seja output=$(clear; do_a_lot_of_output_here).
Kdb

@kdb Boa sugestão! Isso elimina quase completamente a cintilação para mim e é muito mais simples do que a resposta aceita.
Michael Mior

Isso funciona como um encanto! No começo, eu perdi as aspas duplas no 'eco "$ output"', e então as linhas ficam todas confusas. (Todos os espaços em branco são considerados espaços simples.)
Popup

5

O piscar é um resultado inevitável da limpeza da tela sempre que ocorrer o loop. Você pode mover o cursor para o topo da tela e substituir partes da 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 '\033[;H' 
    do_a_lot_of_output_here
    sleep 1
done

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


Nesse caso, o cursor começa a pular para o final da saída a partir da posição aleatória (e artefatos, é claro). Também eu tentei tput clearcom os mesmos resultados (piscando)
ravnur

Adicionei algumas linhas ao script para ocultar o cursor.

Sem cursor - sem pular. Mas sobre artefatos? A saída possui uma quantidade aleatória de linhas. Preciso preencher todos os scripts com espaços antes de iniciar uma nova saída? Mas, de qualquer forma, obrigado por seu tempo e esforços: +1 de mim por isso, mas não resolve o meu problema
ravnur

Eu encontrei apenas uma maneira de se livrar de todos os artefatos: tput ed. Mas causar piscando
ravnur

Qual emulador de terminal você está usando? Com tput edlogo antes da do_a_lot...linha, estou vendo piscando em urxvt, mas não em xterm ou st.

1

Como uma extensão da resposta de Cristian, criei 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ê transmita qualquer comando para o observador. Se você estiver usando git, use git config --global color.status alwayse, em seguida:

watcher git status

Exibe uma saída de status git sempre atualizada.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.