Tengo un comando que crea una salida muy detallada, del orden de cientos de líneas por segundo. Sin embargo, el comando se utiliza \r
para sobrescribir la línea de salida anterior, de forma similar a una barra de progreso. De vez en cuando escribe una nueva línea en la terminal, que "hornea" la línea de salida actual.
Al redirigir esta salida a un archivo, obtengo cientos de megas de salida: cada línea se escribe en el archivo, en lugar de "sobrescribirse" cuando se produce el retorno de carro.
Entiendo que este es el comportamiento esperado y que una forma de resolverlo sería hacer que el programa sea más inteligente y darme cuenta de que está siendo redirigido al archivo y no imprimir este estado interactivo. Sin embargo, no puedo modificar este programa.
¿Hay alguna manera de canalizar/filtrar esta salida para que lo que termine en el archivo de salida final sea lo mismo que vería si lo ejecutara de forma interactiva en la terminal?
He intentado:
spammy_cr_command | uniq
... que produce lo mismo que sinuniq
y también:
spammy_cr_command | sed '/\r/d'
... que también elimina las líneas "preparadas" que contienen el carácter de nueva línea.
Respuesta1
cmd | sed -e 's/.*\r//' > file
Esto reemplazará todo el texto en cada línea seguida por un retorno de carro sin nada, dejando solo la parte de la línea después del retorno de carro final. Esto no esnecesariamenteSin embargo, es lo mismo que quedaría en la terminal, pero es una aproximación cercana la mayor parte del tiempo.
En particular, no se maneja el caso en el que una línea es más larga que su sucesora. Este programa daría resultados incorrectos:
printf 'abcdefg\rxyz\n'
printf '123456789\r\nxyz\n'
porque lo que quedaría visiblemente atrás es
xyzdefg
123456789
xyz
pero sed
también omitiría todos los caracteres no borrados y daría
xyz
xyz
Puede determinar si su programa se comporta así o no. No es raro que las barras de progreso y similares coloquen el cursor en el borde izquierdo, lo que puede no dar el resultado deseado.
Respuesta2
Para una salida TTY-37 muy primitiva, el col
comando resuelve esto sin los problemas sed
mencionados en la respuesta de M. Homer. (Para la salida que no es una simple salida TTY-37 y contiene secuencias de control y escape de terminal, ninguna col
de las dos sed
es la herramienta para el trabajo; pero Stack Exchange ha tenido una sesión de preguntas y respuestas sobreesodesde hace casi ocho años.)
%( printf 'abcdefg\rxyz\n' printf '123456789\r\nxyz\n' ) | col -b xyzdefg 123456789 xyz %
Respuesta3
Se puede hacer algo más parecido al comportamiento de sobrescritura con 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 el ejemplo de Michael Homer:
~ awk 'BEGIN { RS="[\r\n]" } {a = $0 substr(a, 1 + length)} RT ~ /\n/ {print a; a=""}' foo
xyzdefg
123456789
xyz
Se necesita GNU awk para la RT
variable, que contiene el texto separador de registros que coincide con la RS
expresión regular de ese registro.