Kann ich die Pufferung für tr deaktivieren?

10

trscheint seine Eingabe zu puffern, so dass dieser Befehl LongRunningCommand|tr \\n ,erst dann eine Ausgabe erzeugt, wenn sich einige Kilobyte Eingabe von LongRunningCommand angesammelt haben.

Gibt es eine Möglichkeit, trdas Puffern dieser Pufferung oder eines anderen Befehls zu erzwingen , der Zeilenumbrüche ohne Pufferung durch ein anderes Zeichen ersetzen kann?


PS Ich habe bereits die ersten beiden Vorschläge von Puffer in Pipe ausschalten ohne Erfolg ausprobiert .

ndemou
quelle
1
stdbufHaben Sie sich bei LongRunningCommand oder bei tr oder bei beiden unterschiedlich beworben?
Meuh
Für beide gefällt das:stdbuf -o0 fping -aAq -r2 -g 10.30.0.1 10.30.0.255 2>/dev/null | stdbuf -i0 tr \\n ,
ndemou
fping -qsagt "Zeige keine Ergebnisse pro Sonde, sondern nur die endgültige Zusammenfassung", also schreibt es vielleicht nur ein langes Schreiben am Ende?
Meuh
Nein, der Befehl fping funktioniert von alleine einwandfrei. Vielen Dank für die Vorschläge
ndemou
2
Ich denke, das Pufferproblem liegt tatsächlich in der Ausgabe von tr. Versuchen Sie|stdbuf -i0 -o0 tr ...
meuh

Antworten:

12

Befehle puffern ihre Eingabe im Allgemeinen nicht. Sie würden a read()für einen großen Block ausführen, aber wenn beim Lesen aus einer Pipe nicht so viele Bytes in der Pipe vorhanden sind, wird der read()Systemaufruf mit so vielen Zeichen zurückgegeben, wie es vorhanden ist, und die Anwendung arbeitet im Allgemeinen damit, wenn dies möglich ist .

Eine bemerkenswerte Ausnahme ist mawkdie , die so lange bestehen bleibt, read()bis der Eingabepuffer voll ist.

Anwendungen puffern jedoch ihre Ausgabe (stdout). Das übliche Verhalten ist, dass, wenn die Ausgabe auf ein tty geht, die Pufferung zeilenweise erfolgt (das heißt, sie beginnt erst mit dem Schreiben in stdout, wenn eine vollständige Zeile ausgegeben werden muss oder ein Block voll für sehr lange Zeile), während für jeden anderen Dateityp die Pufferung durch Blöcke erfolgt (dh, der Schreibvorgang beginnt erst, wenn ein Block zum Schreiben voll ist (etwa 4 KB / 8 KB) ... hängt von der Software und dem System ab )).

In Ihrem Fall LongRunningCommandpuffert die Ausgabe also wahrscheinlich durch Blöcke (da die Ausgabe eine Pipe und keine tty ist) und trpuffert die Ausgabe wahrscheinlich zeilenweise, da die Ausgabe wahrscheinlich das Terminal ist.

Da Sie jedoch jedes Zeilenumbruchzeichen aus seiner Ausgabe entfernen, wird niemals eine Zeile ausgegeben, sodass die Pufferung blockweise erfolgt.

Hier möchten Sie also die Pufferung für LongRunningCommandund deaktivieren tr. Auf GNU- oder FreeBSD-Systemen:

stdbuf -o0 LongRunningCommand | stdbuf -o0 tr '\n' ,

Beachten Sie, dass es besser ist, die Zeilen mit einem Komma zu verbinden paste -sd , -. Auf diese Weise wird die Ausgabe durch ein Zeilenumbruchzeichen beendet (wahrscheinlich müssen Sie die Pufferung noch deaktivieren).

Stéphane Chazelas
quelle
@mikeserv. Ja, und eine, die stdio-Pufferung verwendet und setvbuf / setbuffer nicht aufruft ... für sich genommen und keine eingebaute Shell ist. Auf GNU- und FreeBSD-Systemen sind jedoch im Allgemeinen alle diese Bedingungen erfüllt.
Stéphane Chazelas
Oh. Ich habe das erst vor ein paar Tagen selbst erfahren, als ich enttäuscht war, dass ich die I / O-Streams für meine statisch kompilierten nicht beeinflussen konnte sed. Entschuldigung, wenn es nervig war - aber ich wusste nicht, dass es Allgemeinwissen war. Ich denke, es verwendet LD_PRELOAD.
Mikesserv
Vielen Dank für die gründliche Erklärung, was Stéphane passiert. Sehr geschätzt
ndemou
5

Um Zeilenumbrüche durch zu ersetzen ",", können Sie ausführen

awk '{ printf "%s,", $0 }'

GNU awk ( gawk) und Solaris nawkwerden mit Zeilenpufferung auf stdin und ohne Pufferung stdout ausgeführt, wenn die Ausgabe an ein Terminal erfolgt. Wenn Ihr awk ist mawk, was unter Ubuntu passiert, können Sie ihm die -W interactiveOption geben , dasselbe Pufferverhalten zu erhalten.

Mark Plotnick
quelle