Benötigen Sie Erklärungen von Hauptbenutzern für dieses unvorhersehbare Verhalten:
ps -eF | { head -n 1;grep worker; }
UID PID PPID C SZ RSS PSR STIME TTY TIME CMD
root 441 2 0 0 0 2 paź15 ? 00:00:00 [kworker/2:1H]
alles sieht in ordnung aus
ls -la / | { head -n 1;grep sbin; }
Zeigt nur die Ausgabe von an head
... Ich habe darüber nachgedacht stdout 2>&1
und arbeite auch nicht für mich. Es ist komisch, irgendwelche Erklärungen oder Vorschläge, wie ich damit umgehen soll.
head
undgrep
machen da nichts.Antworten:
Ich habe einige Nachforschungen angestellt
strace
und es scheint daran zu liegen, wie das Programm auf der linken Seite der Pipeline zum Terminal schreibt. Wenn derls
Befehl ausgeführt wird, werden alle Daten in einem einzigen geschriebenwrite()
. Dies führthead
dazu, dass der gesamte Stdin verbraucht wird.ps
Schreibt dagegen Daten stapelweise aus, sodass nur die ersten vonwrite()
verbraucht werdenhead
und dann vorhanden sind. Bei späteren Aufrufen vonwrite()
wird der neu erzeugtegrep
Prozess aufgerufen .Dies bedeutet, dass es nicht funktionieren würde, wenn der Prozess, nach dem Sie suchen,
grep
nicht im ersten aufgetreten wärewrite()
, dagrep
nicht alle Daten angezeigt werden (es werden sogar weniger als nur die Daten ohne die erste Zeile angezeigt).Hier ist ein Beispiel für den Versuch, auf meinem System nach PID 1 zu suchen:
Ihr
ps -eF
Beispiel funktioniert nur zufällig.quelle
write()
Anrufe tätigen. Wenn der Aufrufhead
nur langsam ausgeführt werden würderead()
(so dass der Pipe-Puffer alle Daten enthält), würde er für beidels
und dasselbe Verhalten aufweisenps
.Dies wird durch Pufferung in glibc verursacht. Im Falle
ls
der Ausgabe befindet sich dieser in einem internen Puffer und wird als solcher nur an weitergereichthead
. Für dieps -eF
ist die Ausgabe größer und so einmalhead
beendet,grep
erhält die folgende die verbleibenden Teile (aber nicht die gesamte) Ausgabe vonps
.Sie können es entfernen, indem Sie die Pipe entpuffern - zum Beispiel mit
sed -u
(ich bin mir nicht sicher, ob es keine GNU-Erweiterung ist):quelle
Was passiert ist, dass
head -n 1
mehr als 1 Zeile liest. Für einen optimalen Durchsatz liest head Teile von Bytes, sodass möglicherweise jeweils 1024 Bytes gelesen werden, und durchsucht diese Bytes dann nach dem ersten Zeilenumbruch. Da der Zeilenumbruch in der Mitte dieser 1024 Bytes auftreten kann, gehen die restlichen Daten verloren. Es kann nicht wieder auf die Pfeife gesetzt werden. Der nächste Prozess, der ausgeführt wird, erhält also nur Bytes 1025 und mehr.Ihr erster Befehl ist zufällig erfolgreich, da der
kworker
Prozess nach dem ersten Teil erfolgt, derhead
gelesen wird.Damit dies funktioniert,
head
müsste jeweils 1 Zeichen gelesen werden. Aber das ist extrem langsam, also nicht.Der einzige Weg, um so etwas effizient zu machen, besteht darin, dass ein einzelner Prozess sowohl "head" als auch "grep" ausführt.
Hierzu gibt es zwei Möglichkeiten:
oder
Es gibt noch viel mehr ...
quelle
Wenn Sie nur die eine oder andere erste Zeile verwenden möchten, funktioniert der folgende Trick und vermeidet die Pufferungsprobleme, die durch die Verwendung von zwei verschiedenen Befehlen zum Lesen des Ausgabestreams verursacht werden:
Das
read
ist in die Shell integriert und verbraucht nicht den gesamten Eingabepuffer, um nur die eine Zeile auszugeben. Wenn Sie also verwenden,read
bleibt der Rest der Ausgabe für den folgenden Befehl übrig.Wenn Sie die Pufferungsprobleme, die in den Beispielen mit zwei verschiedenen Befehlen gezeigt werden, hervorheben möchten, fügen Sie ein hinzu, um die Zeitprobleme
sleep
zu beseitigen, und lassen Sie den Befehl auf der linken Seite alle seine Ausgaben generieren, bevor die Befehle auf der rechten Seite versuchen, einen der Befehle zu lesen es:Nun schlagen beide obigen Beispiele auf die gleiche Weise fehl - der
head
liest einen gesamten Puffer der Ausgabe, nur um die eine Zeile zu erzeugen, und dieser Puffer steht den folgenden nicht zur Verfügunggrep
.Sie können das Pufferungsproblem noch deutlicher erkennen, indem Sie einige Beispiele verwenden, die die Ausgabezeilen nummerieren, damit Sie feststellen können, welche Zeilen fehlen:
Eine einfache Möglichkeit, das Pufferungsproblem zu erkennen, besteht darin
seq
, eine Liste von Zahlen zu erstellen. Wir können leicht erkennen, welche Zahlen fehlen:Meine Tricklösung mit der Shell zum Lesen und Echo der ersten Zeile funktioniert auch mit der hinzugefügten Schlafverzögerung korrekt:
Im Folgenden finden Sie ein vollständiges Beispiel, in dem die
head
Pufferungsprobleme dargestellt sind. Es wird gezeigt, wiehead
ein gesamter Puffer der Ausgabe verbraucht wird, um jeweils nur die fünf Zeilen zu erzeugen. Dieser verbrauchte Puffer ist für den nächstenhead
Befehl in der Sequenz nicht verfügbar :Anhand der
1861
obigen Zahl können wir die Größe des verwendeten Puffers berechnen, indem wirhead
dieseq
Ausgabe von1
bis zählen1860
:Wir sehen, dass
head
das Puffern durch gleichzeitiges Lesen von 8 KB (8 * 1024 Byte) der Pipe-Ausgabe erfolgt, selbst um nur einige Zeilen der eigenen Ausgabe zu erzeugen.quelle