Ich habe einen Befehl, der eine sehr ausführliche Ausgabe erzeugt, in der Größenordnung von Hunderten von Zeilen pro Sekunde. Der Befehl überschreibt jedoch \r
die vorherige Ausgabezeile auf eine Weise, die einem Fortschrittsbalken ähnelt. Gelegentlich schreibt er eine neue Zeile in das Terminal, wodurch die aktuelle Ausgabezeile „gebacken“ wird.
Wenn ich diese Ausgabe in eine Datei umleite, erhalte ich eine Ausgabe im Umfang von Hunderten von Megabyte. Jede Zeile wird in die Datei geschrieben, anstatt beim Wagenrücklauf „überschrieben“ zu werden.
Ich verstehe, dass dies das erwartete Verhalten ist und dass eine Möglichkeit, das Problem zu lösen, darin besteht, das Programm intelligenter zu machen und zu erkennen, dass es zur Datei umgeleitet wird, und diesen interaktiven Status nicht auszudrucken. Ich kann dieses Programm jedoch nicht ändern.
Gibt es eine Möglichkeit, diese Ausgabe umzuleiten/filtern, sodass in der endgültigen Ausgabedatei dasselbe enthalten ist, was ich sehen würde, wenn ich es interaktiv auf dem Terminal ausführen würde?
Ich habe es versucht:
spammy_cr_command | uniq
... was dasselbe Ergebnis liefert wie ohneuniq
und auch:
spammy_cr_command | sed '/\r/d'
... wodurch auch die „gebackenen“ Zeilen gelöscht werden, die das Zeilenumbruchzeichen enthalten.
Antwort1
cmd | sed -e 's/.*\r//' > file
Dadurch wird der gesamte Text in jeder Zeile, auf den ein Wagenrücklauf folgt, durch nichts ersetzt, sodass nur der Teil der Zeile nach dem letzten Wagenrücklauf übrig bleibt. Dies ist nichtNotwendigdas Gleiche, was auf dem Terminal hinterlassen würde, ist aber meistens eine gute Annäherung.
Insbesondere wird der Fall nicht behandelt, dass eine Zeile länger ist als ihre Nachfolgerzeile. Dieses Programm würde falsche Ergebnisse liefern:
printf 'abcdefg\rxyz\n'
printf '123456789\r\nxyz\n'
denn was sichtbar zurückbleibt, ist
xyzdefg
123456789
xyz
aber das sed
würde auch alle nicht gelöschten Zeichen überspringen und geben
xyz
xyz
Sie können bestimmen, ob sich Ihr Programm so verhält oder nicht. Es kommt nicht selten vor, dass Fortschrittsbalken und ähnliches den Cursor am linken Rand verharren lassen, was möglicherweise nicht das gewünschte Ergebnis liefert.
Antwort2
Bei sehr primitiven TTY-37-Ausgaben löst der Befehl dies ohne die in M. Homers Antwort erwähnten col
Probleme . (Für Ausgaben, die keine einfachen TTY-37-Ausgaben sind und Terminal-Escape- und Steuersequenzen enthalten, sind weder noch das richtige Werkzeug für diese Aufgabe; aber Stack Exchange hatte eine Frage-und-Antwort-Runde zused
col
sed
Dasseit fast acht Jahren.)
%( printf 'abcdefg\rxyz\n' printf '123456789\r\nxyz\n' ) | Spalte -b Abonnieren 123456789 xyz %
Antwort3
Etwas, das dem Überschreibverhalten näher kommt, kann mit GNU awk erreicht werden:
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 = ""
}
Am Beispiel von Michael Homer:
~ awk 'BEGIN { RS="[\r\n]" } {a = $0 substr(a, 1 + length)} RT ~ /\n/ {print a; a=""}' foo
xyzdefg
123456789
xyz
GNU awk wird für die RT
Variable benötigt, die den Datensatztrenntext enthält, der mit dem RS
regulären Ausdruck für diesen Datensatz übereinstimmt.