Bei der Verwendung von Rohren zum Beispiel
sudo cat /dev/sda | strings | less
Ich kann mich in den Stringzeilen meines SDA-Geräts bewegen. Aber werden die Inhalte des SDA-Geräts vollständig geladen und in den Ausgabestream von cat ausgegeben? Oder werden die neuen Zeilen ausgewertet, wenn ein Programm eine Ausgabe von cat anfordert? (d. h. ich drücke „J“ auf dem Less-Pager)
Antwort1
Dies hat mehr mit dem Wie zu tun less
als mit dem Wie cat
oder strings
Arbeiten.
Der cat
Befehl überträgt Daten nur an seine Standardausgabe und wird blockiert, wenn der Pipe-Puffer zwischen ihm und strings
voll ist und niemand liest. cat
führt selbst nur minimale Pufferung durch und der Pipe-Puffer ist normalerweise klein.
Dies gilt auch für strings
. Es verarbeitet die Daten von cat
und blockiert, wenn less
die von ihm erzeugten Daten nicht gelesen werden strings
.
less
puffert seine Eingabe, damit Sie in den angezeigten Daten vor- und zurückblättern können. Wenn Sie zur nächsten Seite scrollen, less
liest mehr Daten aus strings
seinem Puffer. Wenn Sie nicht vorwärts scrollen, liest meiner Meinung nach less
nur eine begrenzte Datenmenge (und wird daher strings
blockiert cat
, wenn Sie nicht vorwärts scrollen).
Wenn Sie eine große Datenmenge an weiterleiten less
, wird für diese Pufferung ziemlich viel Speicher verwendet.WennSie beschließen, alles bis zum Ende durchzulesen less
.
Es gibt eine Option -B
, die die Speichermenge, die zum Puffern verwendet wird, auf 64 Kilobyte begrenzt (oder auf die von Ihnen mit der -b
Option angegebene Menge). Wenn Sie die Puffergröße auf diese Weise begrenzen, können Sie nicht weiter zurückblättern, als der angegebene Pufferspeicherplatz aufnehmen kann. Sie können aber auch große Datenmengen lesen, ohne dass less
der Speicher ausgeht.
Siehe auch man less
auf Ihrem System.
Antwort2
Pipes haben begrenzten Pufferspeicherplatz, und wenn ein Pipe-Reader (wie less
in Ihrem Beispiel) keine weiteren Daten aus der Pipe liest, wird der Writer nach dem Füllen des Puffers blockiert. Dies wirkt sich auf den strings
Befehl aus, der wiederum den Befehl blockiert, cat
nachdem seine Pipe voll ist.
Natürlich kann der cat
Befehl nicht den gesamten Inhalt des SDA-Geräts in den Hauptspeicher lesen. Wenn also Blöcke geändert werden, die noch nicht von ihm gelesen wurden, cat
werden die geänderten Inhalte angezeigt.
Antwort3
Sowohl cat
als auch strings
und die meisten ähnlichen Dienstprogramme¹ lesen jeweils eine kleine Eingabe, verarbeiten sie, lesen dann weitere Eingaben usw. In Ihrem Fall cat
liest es also nur das , was less
angezeigt wird, plus ein wenig mehr, was unterwegs ist.
Genauer gesagt cat
ist die grundlegende Funktionsweise:
- Reservieren Sie einige Kilobyte Speicher zur Verwendung als Puffer.
- Es stehen noch weitere Eingabemöglichkeiten zur Verfügung:
- Liest bis zu N Bytes an Eingaben in den Puffer. (Dadurch werden Daten überschrieben, die in einem vorherigen Zyklus ausgegeben wurden.)
- Schreibt den Pufferinhalt in die Ausgabe.
Der Schreibvorgang blockiert, bis ein Platz zum Kopieren der Ausgabe vorhanden ist. Wenn die Ausgabe einer Pipe erfolgt, verbraucht die Pipe selbst ein wenig Speicher im Kernel, was alsRohrpuffer. Wenn dieser voll ist, cat
wird der Schreibversuch blockiert, wenn versucht wird, in die Pipe zu schreiben, bis Platz ist. Im Pipe-Puffer kann Platz sein, wenn der Prozess am Leseende der Pipe einige Daten liest.
Das strings
Programm funktioniert genauso wie cat
, mit dem Unterschied, dass es nicht die gesamte Eingabe kopiert, sondern nur ausgewählte Teile.
Das less
Programm funktioniert etwas anders: Es behält alles, was es liest, im Speicher. Es recycelt seinen Puffer nicht, sondern vergrößert ihn, solange weitere Eingaben eingehen. Der Leseteil ist jedoch insofern ähnlich, als dass er less
Daten nur liest, wenn er sie benötigt: Er liest nur bis zur letzten angezeigten Zeile und zusätzlich noch ein wenig mehr, falls verfügbar.
Wenn Sie also ausführen , besteht sudo cat /dev/sda | strings | less
der Lesevorgang aus Folgendem:/dev/sda
- Daten, die
less
bereits angezeigt wurden (oder vorbeigescrollt sind). - Bis zu einigen KB an Daten, die
less
gelesen, aber noch nicht angezeigt wurden. - Bis zu einigen kB im Pipe-Puffer zwischen
strings
undless
. - Bis zu einigen kB im Speicher von
strings
. - Bis zu einigen kB im Pipe-Puffer zwischen
cat
undstrings
. - Bis zu einigen kB im Speicher von
cat
.
Sie können beobachten, wann jedes Programm Daten liest und schreibt, indem Sie seine Systemaufrufe verfolgen:
sudo strace -e read,write -o cat.strace cat /dev/sda | strace -e read,write -o cat.strace strings | strace -e read,write -o less.strace less
und beobachten Sie die *.strace
Dateien. Sie können auch überprüfen, wie viel cat
gelesen wurde, indem Sie den Dateioffset überprüfen, beispielsweise mit lsof -p1234
oder mit head /proc/1234/fdinfo/0
wobei 1234
die Prozess-ID von ist cat
.
¹ Die wichtigste Ausnahme unter den grundlegenden Textverarbeitungsprogrammen ist , sort
das keine Ausgabe ausgeben kann, bis es die gesamte Eingabe gelesen hat: Nach allem, was es weiß, kann die erste Ausgabezeile durchaus auch die letzte Eingabezeile sein, die es erreicht.
Antwort4
Auf einigen Systemen (z. B. MS-Dos) wird die Pipe implementiert, indem die Ausgabe des ersten Befehls in eine Datei kopiert und dann der zweite Befehl ausgeführt wird, um aus dieser Datei zu lesen. Unix macht das nicht so.
Unter Unix ist es wie eine Produktionsstraße. Jede Stufe arbeitet gleichzeitig, liest Eingaben und erzeugt Ausgaben. Wenn Prozess A schneller produziert als Prozess B verbraucht, dann gibt es einen Lagerbestand zwischen Prozess A und B. Wenn dieser zu groß ist (½ KiB bis 4 KiB), wird Prozess A angehalten. Wenn B keinen Lagerbestand mehr zu verarbeiten hat, wird B angehalten. Prozesse werden angehalten und wieder aufgenommen, um die Lagerbestände niedrig zu halten.
Der Code in diesen Programmen kümmert sich um nichts davon. Er liest nur die Eingabe und schreibt die Ausgabe. Wenn er versucht zu lesen, bevor Daten verfügbar sind, oder versucht zu schreiben, bevor der nächste Prozess bereit ist, wird er vom Betriebssystem angehalten, bis er bereit ist.
Wenn nichts mehr zu lesen ist (und nichts mehr unterwegs ist), erhält der Reader ein Dateiende und wird beendet. Dies wiederum löst im nächsten Prozess ein Dateiende aus.