Eu tenho um comando que cria uma saída muito detalhada, da ordem de centenas de linhas por segundo. No entanto, o comando \r
substitui 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 sed
també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 col
comando resolve isso sem os problemas sed
mencionados 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
é sed
a 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 RT
variável, que contém o texto do separador de registro que corresponde ao RS
regex desse registro.