Ich verstehe nicht, wie die Daten in der Pipeline fließen und hoffe, jemand könnte klären, was dort vor sich geht.
Ich dachte, eine Pipeline von Befehlen verarbeitet Dateien (Text, Arrays von Strings) zeilenweise. (Wenn jeder Befehl Zeile für Zeile ausgeführt wird.) Jede Textzeile durchläuft die Pipeline. Befehle warten nicht auf die vorherige, um die Verarbeitung der gesamten Eingabe abzuschließen.
Es scheint aber nicht so zu sein.
Hier ist ein Testbeispiel. Es gibt einige Textzeilen. Ich schreibe sie in Großbuchstaben und wiederhole jede Zeile zweimal. Ich mache das mit cat text | tr '[:lower:]' '[:upper:]' | sed 'p'
.
Um den Vorgang zu verfolgen, können wir ihn "interaktiv" ausführen - überspringen Sie den eingegebenen Dateinamen cat
. Jeder Teil der Pipeline verläuft zeilenweise:
$ cat | tr '[:lower:]' '[:upper:]'
alkjsd
ALKJSD
sdkj
SDKJ
$ cat | sed 'p'
line1
line1
line1
line 2
line 2
line 2
Die gesamte Pipeline wartet jedoch darauf, dass ich die Eingabe mit beende EOF
und gibt erst dann das Ergebnis aus:
$ cat | tr '[:lower:]' '[:upper:]' | sed 'p'
I am writing...
keep writing...
now ctrl-D
I AM WRITING...
I AM WRITING...
KEEP WRITING...
KEEP WRITING...
NOW CTRL-D
NOW CTRL-D
Soll es so sein Warum ist es nicht Zeile für Zeile?
cat
puffert, bis stdin sich schließt.tr
undsed
verarbeite Zeilencat
bevor stdin schließtAntworten:
Es gibt eine allgemeine Pufferregel, die von der C-Standard-E / A-Bibliothek (
stdio
) befolgt wird, die die meisten Unix-Programme verwenden. Wenn die Ausgabe an ein Terminal gesendet wird, wird sie am Ende jeder Zeile gelöscht. Andernfalls wird es nur geleert, wenn der Puffer (8 KB auf meinem Linux / amd64-System; könnte bei Ihnen anders sein) voll ist.Wenn alle Dienstprogramme , die allgemeine Regel folgende, würden Sie die Ausgabe in alle Ihre Beispiele sehen verzögert (
cat|sed
,cat|tr
undcat|tr|sed
). Aber es gibt eine Ausnahme: GNUcat
puffert niemals seine Ausgabe. Entweder wirdstdio
die Standardpufferrichtlinie nicht verwendet oder geändertstdio
.Ich kann ziemlich sicher sein, dass Sie GNU
cat
und kein anderes Unix verwenden,cat
da sich die anderen nicht so verhalten würden. Herkömmliches Unixcat
bietet die-u
Möglichkeit, ungepufferte Ausgaben anzufordern. GNUcat
ignoriert die-u
Option, da die Ausgabe immer ungepuffert ist.Wenn Sie also eine Pipe mit einem
cat
links im GNU-System haben, wird der Durchgang von Daten durch die Pipe nicht verzögert. Dascat
geht nicht mal Zeile für Zeile - das macht Ihr Terminal. Während Sie Eingaben für cat eingeben, befindet sich Ihr Terminal im "kanonischen" Modus - zeilenbasiert. Mit Bearbeitungstasten wie Rücktaste und Strg-U haben Sie die Möglichkeit, die eingegebene Zeile vor dem Senden zu bearbeiten Enter.In diesem
cat|tr|sed
Beispiel werdentr
weiterhin Daten von empfangen,cat
sobald Sie auf drücken Enter, estr
wird jedoch diestdio
Standardrichtlinie befolgt: Die Ausgabe wird an eine Pipe gesendet, sodass nicht nach jeder Zeile eine Leerung erfolgt. Es schreibt in die zweite Pipe, wenn der Puffer voll ist oder wenn eine EOF empfangen wird, je nachdem, was zuerst eintritt.sed
folgt ebenfalls derstdio
Standardrichtlinie, aber die Ausgabe wird an ein Terminal gesendet, sodass jede Zeile geschrieben wird, sobald sie fertig ist. Dies hat Auswirkungen darauf, wie viel Sie eingeben müssen, bevor etwas am anderen Ende der Pipeline angezeigt wird. Wennsed
Sie die Ausgabe blockpuffern, müssen Sie doppelt so viel eingeben (umtr
den Ausgabepuffer undsed
die Ausgabe zu füllen) Puffer).GNU
sed
hat die-u
Option, dass, wenn Sie die Reihenfolge umkehren und verwendencat|sed -u|tr
, die Ausgabe sofort wieder angezeigt wird. (Diesed -u
Option könnte an anderer Stelle verfügbar sein, aber ich glaube nicht, dass es sich um eine alte Unix-Tradition handelt.cat -u
) Soweit ich das beurteilen kann, gibt es für keine entsprechende Optiontr
.Es gibt ein Hilfsprogramm, mit
stdbuf
dem Sie den Puffermodus jedes Befehls ändern können, der diestdio
Standardeinstellungen verwendet. Es ist ein bisschen zerbrechlich, da es verwendet wirdLD_PRELOAD
, um etwas zu erreichen, für das die C-Bibliothek nicht entwickelt wurde, aber in diesem Fall scheint es zu funktionieren:quelle
tee
unddd
normalerweise auch nach ihren eigenen Regeln spielen. Wenn diese drei Werkzeuge phantasievoll kombiniert werden, können sie praktisch jede Notwendigkeit fürstdbuf
Pipelines im Hintergrund zunichte machen.Das hat mich tatsächlich einige Gedanken gekostet, um zu verstehen und noch mehr, um zu antworten. Tolle Frage (ich werde es als nächstes bewerten).
Sie haben es versäumt,
tr | sed
Ihre obigen Debugging-Elemente einzugeben:Also offenbar
tr
Puffer. Lerne jeden Tag etwas Neues!EDIT :
Während ich darüber nachdenke, haben wir die Ursache isoliert, aber keine Erklärung geliefert. Wenn Sie
cat | tr
, schreibt es sofort, wenn Siecat | sed
, es sofort schreibt, aber wenn Sietr | sed
, es wartet fürEOF
. Ich würde vorschlagen, dass die Antwort intr
oder imsed
Quellcode vergraben ist und kein Pipe-Problem darstellt.EDIT :
Ich sehe, dass Wumpus die Erklärung geliefert hat, während ich die letzte Änderung getippt habe. Vielen Dank!
quelle
stdbuf
was auch hilfreich sein könnte. unix.stackexchange.com/questions/182537/…