Como alterar o conteúdo de uma linha no terminal em vez de escrever uma nova?

22

Assim, quando wget obtém uma página da Web, ela mostra uma barra de status que indica quanto o arquivo é baixado. Parece assim:

25%[=============>______________________________________] 25,000 100.0K/s (sublinhados são espaços; eu simplesmente não consegui descobrir como obter mais de um espaço consecutivo lá)

No entanto, em vez de escrever outra linha para stdout e adicionar outra barra de progresso, ela é atualizada assim:

50%[===========================>________________________] 50,000 100.0K/s

E wget também não é o único exemplo disso. Por exemplo, quando você canaliza algo para less e, em seguida, sai, o prompt original ainda está lá, junto com o resultado dos comandos que você executou anteriormente. É como se você nunca tivesse saído.

Então, minhas perguntas são, como isso é chamado, como posso implementá-lo? Ele só funciona para uma única linha de cada vez? Posso usar isso em C?

    
por fouric 14.07.2012 / 22:03

2 respostas

30

Em primeiro lugar, a sua pergunta não tem nada a ver com o bash, mas com o terminal. O terminal está respondendo por exibir o texto dos programas e o próprio bash não tem controle sobre os programas depois que eles são lançados.

Terminais oferecem sequências de controle para controlar cor, fonte, posição do cursor e mais. Para uma lista de seqüências de terminais padronizadas, veja link Você pode, por exemplo,

  • posicione o cursor no início da linha
  • exclua a linha depois
  • escreva uma nova linha

para criar uma barra de progresso.

Sequências de escape de terminal mais avançadas são tipicamente terminais dependente, e. trabalhe apenas com Eterm ou xterm. ncurses -  é uma biblioteca de programação que para crie programas interativos com o terminal para que você não precise usar sequências de escape.

Como sobrescrever uma linha existente com sequências de terminal

echo long text
sleep 1
printf "3[1A"  # move cursor one line up
printf "3[K"   # delete till end of line
echo foo

Como sobrescrever uma linha existente sem seqüência de terminal

Uma solução simples é não escrever uma nova linha no final, mas escrever o retorno de carro, que basicamente redefine o cursor para o início da linha, por exemplo:

echo -n first 
sleep 1 
echo -ne "\rsecond"
echo

O \r ou o retorno de carro colocará o cursor no início da linha e permitirá que você sobrescreva o conteúdo da linha.

Alternar entre buffers como less ou vi

O comportamento de less também é devido a um recurso de terminal mais avançado, o tela alternativa:

In VT102 mode, there are escape sequences to activate and deactivate an alternate screen buffer, which is the same size as the display area of the window. When activated, the current screen is saved and replaced with the alternate screen. Saving of lines scrolled off the top of the window is disabled until the normal screen is restored. The term‐ cap(5) entry for xterm allows the visual editor vi(1) to switch to the alternate screen for editing and to restore the screen on exit. A popup menu entry makes it simple to switch between the normal and alternate screens for cut and paste.

link lista alguns exemplos de como fazer você mesmo, seja através de tput ou por meio de alguma fuga seqüências.

    
por 15.07.2012 / 01:35
14

Em vez de usar echo , que anexa automaticamente uma nova linha à string, use printf "%s\r" whatever - o retorno de carro envia o cursor para o início da linha atual. exemplo:

seq 1 15 | while read num; do printf "%2d\r" $num; sleep 1; done; echo ""
    
por 15.07.2012 / 01:20

Tags