Lassen Sie das T-Stück besser mit Wagenrückläufen umgehen

748
sjngm

Ich habe eine Java-Konsolenanwendung geschrieben, die ihren Status mehrmals mit Wagenrückläufen (\ r) am Ende anstatt mit Zeilenvorschüben (\ n) an die Konsole druckt, um die Ausgabe auf einem Bildschirm zu erhalten. Ich möchte diese Ausgabe auch in eine Datei leiten, z

java -jar my-jar.jar | tee /tmp/my-jar.log 

Es macht jedoch keinen Sinn, alles in diese Datei zu schreiben, nur was am Ende der Anwendung sichtbar ist. Mit anderen Worten, ich brauche nicht alle "Zeilen", die mit \ r dort enden.

Beispiel: Ich Code

System.out.print("hello\r") Thread.sleep(2000); System.out.println("world") 

"Hallo" erscheint auf dem Bildschirm und wird nach zwei Sekunden durch "Welt" ersetzt. Daher sieht der Benutzer nach dem Programmende nur "Welt" auf dem Bildschirm. Gut, das ist richtig.

Wenn ich das zu einer Datei zusammenstelle, wird "hallo \ rworld \ n" angezeigt, aber es soll nur "world \ n" enthalten.

Wie mache ich das auf der Kommandozeile, anstatt das Programm in Java zu programmieren (warum ist die Frage hier und nicht in SO)?

2

2 Antworten auf die Frage

2
John1024

Mit sed

sedLiest standardmäßig eine durch Zeilenumbruch getrennte Eingabe. Dieser Befehl entfernt alles vor dem letzten \rin einer Zeile:

sed 's/.*\r//' 

Zum Beispiel:

$ echo $'line1\n\hi\rhello\rworld' | sed 's/.*\r//' line1 world 

Um dies mit zu verwenden tee, können wir Prozessersetzung verwenden :

echo $'line1\n\hi\rhello\rworld' | tee >(sed 's/.*\r//' >Outfile) 

Unter bash wird das Konstrukt >(...)als Prozessersetzung bezeichnet . Die Befehle werden in den Parens ausgeführt und in ein dateiähnliches Objekt eingefügt. teeSchreiben Sie in das dateiähnliche Objekt und die Befehle verarbeiten die Eingabe.

Awk verwenden

In ähnlicher Weise entfernt dies alles vor dem letzten \rin einer durch Zeilenumbrüche getrennten Zeile:

awk -F'\r' '' 

Die Option -F'\r'setzt das Feldtrennzeichen auf einen Wagenrücklauf. $NFDaher möchten wir nur das letzte Feld in jeder Zeile mit Zeilenumbruch drucken. Somit ist print $NF.

Zum Beispiel:

$ echo $'line1\n\hi\rhello\rworld' | awk -F'\r' '' line1 world 

Um dies mit zu verwenden tee:

echo $'line1\n\hi\rhello\rworld' | tee >(awk -F'\r' '' >Outfile) 
Danke für die ausführliche Erklärung! Ich bewundere wirklich diejenigen, die das ganze Umleitungs-Subshell-Zeug verstehen und ihre Syntax kennen ... Ich habe es an Ihrem letzten Beispiel versucht und es scheint aufgrund der großen Anzahl von Zeichen in einer solchen Zeile besser zu funktionieren als sed. sjngm vor 7 Jahren 1
Ich denke, ich muss darauf zurückkommen. Ich ging zu Ihrem letzten Beispiel, und ich habe gelernt, dass dies die Ausgabe irgendwie puffert und am Ende des Programms in einem Schritt in "Outfile" schreibt. Gibt es eine Möglichkeit, das Schreiben nach jedem gefundenen `\ n` zu erzwingen? Wie in "Schreiben Sie jede Zeile, sobald Sie sie haben" in "Outfile"? sjngm vor 7 Jahren 0
Manchmal ist es schwierig, herauszufinden, wo der lästige Puffer liegt. Versuchen Sie zunächst einmal: `awk -F '\ r' ' "> outfile" John1024 vor 7 Jahren 1
Ja, ich denke das hat es getan. Danke noch einmal :) sjngm vor 7 Jahren 1
1
Jaakko

Ich konnte ein ähnliches Problem mit col (Filter Reverse Line Feeds von Eingabe) lösen .

java -jar my-jar.jar | tee >(col -pb >/tmp/my-jar.log)

BEARBEITEN: Verfeinerte Antwort, um die Frage besser zu treffen.

"Ja wirklich?" Damit sehe ich kein "Hallo" auf dem Bildschirm: `(Echo -de" Hallo \ r "; Schlaf 2; Echo" Welt ") | col -pb` sjngm vor 7 Jahren 0
Ich denke, das liegt an den Klammern, die den gesamten Code in ihnen ausführen, bevor er an den nächsten weitergeleitet wird. Wenn Sie die Klammern herausnehmen, scheint es sich wie erwartet zu verhalten: `echo -en" hallo \ r "; schlaf 2; Echo "Welt" | col -pb`. Das vorherige kann auch in einer Datei protokolliert werden, indem die Pipe mit "tee" erweitert wird, was nur "world" in der Protokolldatei ergibt. Jaakko vor 7 Jahren 0
Nun, das sollte der Code tun. Entweder suchten Sie nach einer Lösung für ein anderes Problem oder verstanden meine Frage nicht. sjngm vor 7 Jahren 0
Ich verstehe, was Sie meinen, ich habe die Antwort geändert, um die Bash-Prozessersetzung zu verwenden. Auf diese Weise sehen Sie "Hallo" in der Konsole und "Welt" in der Protokolldatei. Jaakko vor 7 Jahren 0
Ja, das funktioniert :) sjngm vor 7 Jahren 0