Como excluir uma linha com eco?

60

Eu sei que poderia excluir os três últimos caracteres com:

echo -ne '\b\b\b'

Mas como posso excluir uma linha completa? Quero dizer, não quero usar:

echo -ne '\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b'

... etc ... para excluir uma linha longa.

LanceBaynes
fonte
2
Para quem gostaria de escrever continuamente na mesma linha: echo -ne "\033[2K" ; printf "\r"agora a linha é nova como se nunca tivesse sido escrita antes.
Olá Mundo
2
Tenho certeza que você pode apenas usar echo -ne "\e[2K\r". Mas as seqüências de escape ANSI FTW, no entanto.
Parthian Shot
Consulte também Por que o printf é melhor que o eco?
Curinga

Respostas:

57

Você pode usar \bou \rpara mover o cursor para trás e substituir o caractere impresso por um novo. Observe que \bnem \rexclui nem os caracteres impressos. Apenas move o cursor para trás. \bmove o cursor para trás um caractere e \rmove o cursor para o início da linha.

Exemplo: ambos

echo -e 'foooo\b\b\b\b\bbar'

e

echo -e 'foooo\rbar'

irá imprimir:

baroo

Se você deseja excluir os caracteres, use a seguinte solução alternativa:

echo -e 'fooooo\r     \rbar'

resultado:

bar  

Trecho de man echo:

   If -e is in effect, the following sequences are recognized:

   \0NNN  the character whose ASCII code is NNN (octal)

   \\     backslash

   \a     alert (BEL)

   \b     backspace

   \c     produce no further output

   \f     form feed

   \n     new line

   \r     carriage return

   \t     horizontal tab

   \v     vertical tab

   NOTE: your shell may have its own version of echo, which usually super‐
   sedes the version described here.  Please refer to your  shell's  docu‐
   mentation for details about the options it supports.
lesmana
fonte
4
Sim, mas echo -e 'fooooooooo\rbarecoa barooooooo.
Mat
11
Sim você está certo. Observe que echo -e 'foooo\b\b\b\b\b\b\b\b\b\bbar'também ecoa baroo.
Lesmana
Tão doce, funciona mesmo perfeitamente printf.
Michael-O
4
Resposta muito imprecisa. Um de Kevin é realmente melhor
Mike Aski
87

Você está procurando escapes terminais . Em particular, para limpar da posição do cursor até o início da linha:

echo -e "\033[1K"

Ou tudo na linha, independentemente da posição do cursor:

echo -e "\033[2K"

E você também pode fazer todos os tipos de truques com fugas de terminal.

Kevin
fonte
6
Isso pressupõe um terminal ou emulador compatível com VT100 (que atualmente é uma suposição bastante segura).
Keith Thompson
2
Se você quiser apagar algo que você simplesmente repetiu, seu eco anterior deve ter a opção -n, ou você vai ser enviado para uma nova linha
djjeck
11
Se você quiser escrever outra coisa, na linha que você está apagando, adicione um sinalizador -n no eco acima, ou então você irá para uma nova linha logo após excluí-la. Além disso, anexe a \ r à sequência acima ou o seu novo conteúdo não irá para o início dessa linha.
djjeck
-1 -ecomo o echoargumento não é compatível com POSIX + eu não gosto das seqüências de escape. Ou prefere printfou tput.
LinuxSecurityFreak
@Vlastimil Por que você rebaixou isso? O OP não pediu uma resposta que você gostaria. Talvez ele devesse ter precised que -eparâmetro para echonão é compatível com POSIX, mas ainda assim ...
Souki
35

Se você deseja limpar a linha, sugiro que você use uma combinação do retorno de carro que as pessoas estão mencionando e terminfo.

# terminfo clr_eol
ceol=$(tput el)
echo -ne "xyzzyxyzzy\r${ceol}foobar"

Isso escreverá xyzzyxyzzy, retornará ao início da linha e enviará a sequência "limpar até o final da linha" para o terminal e, em seguida, escreverá foobar. O -nmake echo não adiciona uma nova linha após o foobar.

Arcege
fonte
4
Gosto do tipo de parte preparada para o futuro dessa solução específica - usar tput possivelmente significa que funcionará em qualquer tipo de terminal.
Amos Shapira
2
Melhor quanto printf '%s\r%s%s' xyzzyxyzzy "$ceol" foobarà portabilidade e evitar o conteúdo de $ceolpassar pela \xexpansão.
Stéphane Chazelas
Melhor resposta, apenas porque funciona com linhas arbitrariamente longas. Obrigado!
Raphael
trabalho perfeito. Mas se eu redimensionar a tela do terminal menor que a linha de saída, ela ficará confusa.
K.Sopheak
11

Você solicitou explicitamente echo, mas esta solicitação o define. Aqui está uma abordagem que usa o printfcomando embutido do bash com expansão de chaves:

printf 'fooooooooo' # 10 characters
printf '\r'; printf ' %0.s' {0..9} # 10 expansions of the space character
kojiro
fonte
11
perfeito! exatamente o que eu precisava #
Omar S.
2
printf 'Status: iniciado'; sono 2s; printf '\ r'; printf 'Status: atualizado'; sono 2s; printf '\ r';
Omar S.
4

Aqui está um exemplo usando as opções de nova linha -n e retorno de carro da echo \r.

substituir linha terminal do bash

#!/bin/bash

CHECK_MARK="\033[0;32m\xE2\x9C\x94\033[0m"

echo -e "\n\e[4mDoing Things\e[0m"
echo -n "doing thing 1..."
sleep 1
echo -e "\\r${CHECK_MARK} thing 1 done"
Derek Soike
fonte
A marca de seleção funciona mesmo no RHEL6. Agradável por edições puramente estéticas dos meus scripts
oneindelijk
1

Em vez de echo -en "\r"você também pode achar o printf "\r"comando útil. Dessa forma, você pode formatar a sequência. por exemplo:

for sec in {1..100}; do printf "\r %04d" ${sec}; sleep 0.1; done

Eu costumo fazer isso também ao operar com análise lenta de arquivos para exibir o nome do arquivo atualmente em andamento sem criar uma lista

McPeppr
fonte
-1 Talvez você queira criar intencionalmente uma linha, mas isso é realmente bom apenas para testes. Eu o reescreveria corretamente com novas linhas.
LinuxSecurityFreak
0

Como pergunta é excluir a linha completa

Eu usei o comando abaixo com a combinação de echoe sedpara excluir a linha

Após a execução do comando, o resultado ficará vazio. Desde que a linha seja substituída por nenhuma

comando

echo  "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b" | sed -r "s/.*//g"
Praveen Kumar BS
fonte
-1

Aqui está um exemplo de temporizador que eu uso:

i=10
while [ $i -gt 0 ]; 
do 
  printf "$i seconds remaining       " && printf '\r\033[1B'
  i=`expr $i - 1`
  sleep 1
  printf '\033[1A'
done
mikiemorales
fonte
-1 Talvez você queira criar intencionalmente uma linha, mas isso é realmente bom apenas para testes. Eu o reescreveria corretamente com novas linhas.
LinuxSecurityFreak
Em seguida, faça isso e adicione uma nova resposta. Ou proponha uma edição da minha resposta.
Mikiemorales