Redirecionando a saída que envia spam ao terminal com retornos de carro

Redirecionando a saída que envia spam ao terminal com retornos de carro

Eu tenho um comando que cria uma saída muito detalhada, da ordem de centenas de linhas por segundo. No entanto, o comando \rsubstitui a linha de saída anterior, de maneira semelhante a uma barra de progresso. Ocasionalmente, ele grava uma nova linha no terminal, que "prepara" a linha de saída atual.

Ao redirecionar essa saída para um arquivo, recebo centenas de megas de saída - cada linha é gravada no arquivo, em vez de ser 'sobrescrita' quando ocorre o retorno de carro.

Entendo que esse é o comportamento esperado, e que uma forma de resolver isso seria deixar o programa mais inteligente, e perceber que ele está sendo redirecionado para o arquivo e não imprimir esse status interativo. No entanto, não posso modificar este programa.

Existe alguma maneira de canalizar/filtrar essa saída para que o que acabe no arquivo de saída final seja o mesmo que eu veria se o executasse interativamente no terminal?

Eu tentei:

spammy_cr_command | uniq

... que produz o mesmo que semuniq

e também:

spammy_cr_command | sed '/\r/d'

... que exclui as linhas "preparadas" que também contêm o caractere de nova linha.

Responder1

cmd | sed -e 's/.*\r//' > file

Isso substituirá todo o texto em cada linha seguida por um retorno de carro por nada, deixando apenas a parte da linha após o retorno de carro final para trás. Isso não énecessariamenteo mesmo que seria deixado no terminal, mas é uma aproximação na maioria das vezes.


Em particular, o caso em que uma linha é mais longa que a sua sucessora não é tratado. Este programa daria resultados incorretos:

printf 'abcdefg\rxyz\n'
printf '123456789\r\nxyz\n'

porque o que ficaria para trás visivelmente é

xyzdefg
123456789
xyz

mas sedtambém pularia todos os caracteres não apagados e daria

xyz

xyz

Você pode determinar se o seu programa se comporta assim ou não. Não é incomum que barras de progresso e similares coloquem o cursor na borda esquerda, o que pode não fornecer o resultado desejado.

Responder2

Para saída TTY-37 muito primitiva, o colcomando resolve isso sem os problemas sedmencionados na resposta de M. Homer. (Para saída que não é uma saída TTY-37 simples e contém sequências de escape e controle de terminal, nem colé seda ferramenta para o trabalho; mas o Stack Exchange teve uma sessão de perguntas e respostas sobrequejá há quase oito anos.)

%(
printf 'abcdefg\rxyz\n'
printf '123456789\r\nxyz\n'
) | col -b
xyzdefg
123456789
xyz
%

Responder3

Algo mais próximo do comportamento de substituição pode ser feito com GNU awk:

BEGIN { 
  RS = "[\r\n]"                   # split records on either CR or LF
  a = ""                          # variable to save the text for overwriting
} 
{
  a = $0 substr(a, 1 + length)    # save current line, add trailing part of saved text
} 
RT ~ /\n/ {                       # LF, time to print and reset
  print a;
  a = ""
}

Usando o exemplo de Michael Homer:

~ awk 'BEGIN { RS="[\r\n]" } {a = $0 substr(a, 1 + length)} RT ~ /\n/ {print a; a=""}' foo
xyzdefg
123456789
xyz

GNU awk é necessário para a RTvariável, que contém o texto do separador de registro que corresponde ao RSregex desse registro.

informação relacionada