Liest tail die ganze Datei?

113

Wenn ich taileine 25 GB große Textdatei haben möchte, liest der tailBefehl dann die gesamte Datei?

Da eine Datei auf einer Festplatte verstreut sein könnte, stelle ich mir das vor, aber ich verstehe solche Interna nicht gut.

Die unfun Katze
quelle

Antworten:

119

Nein, tailes wird nicht die gesamte Datei gelesen, es wird bis zum Ende gesucht und dann werden die Blöcke rückwärts gelesen, bis die erwartete Anzahl von Zeilen erreicht wurde. Anschließend werden die Zeilen in der richtigen Richtung bis zum Ende der Datei angezeigt und möglicherweise wird die Datei weiterhin überwacht Datei, wenn die -fOption verwendet wird.

Beachten Sie jedoch, dass tailes keine andere Wahl gibt, als die gesamten Daten zu lesen, wenn eine nicht suchbare Eingabe bereitgestellt wird, beispielsweise beim Lesen aus einer Pipe.

Wenn Sie aufgefordert werden, nach Zeilen zu suchen, die am Anfang der Datei beginnen, wird bei Verwendung der tail -n +linenumberSyntax- oder tail +linenumberNicht-Standardoption tail(sofern unterstützt) offensichtlich die gesamte Datei gelesen (sofern nicht unterbrochen).

jlliagre
quelle
14
Verdammt zu schnell :-). Hier ist der relevante Quellcode . Gibt die letzten N_LINES Zeilen vom Ende der Datei FD aus. Gehen Sie die Datei rückwärts durch und lesen Sie jeweils "BUFSIZ" -Bytes (außer wahrscheinlich das erste), bis Sie den Anfang der Datei erreicht haben oder NUMBER Zeilenumbrüche gelesen haben.
Patrick
1
Außerdem tail +nwird die gesamte Datei gelesen - zuerst, um die gewünschte Anzahl von Zeilenumbrüchen zu finden, dann, um den Rest auszugeben.
SF.
@SF. Antwort in der Tat aktualisiert.
Juli
4
Beachten Sie, dass nicht alle tailImplementierungen dies tun oder ordnungsgemäß ausführen. Zum Beispiel ist busybox 1.21.1 tailin dieser Hinsicht defekt. Beachten Sie auch, dass sich das Verhalten ändert, wenn tailstdin und stdin eine reguläre Datei ist und die anfängliche Position in der Datei nicht am Anfang steht, wenn tailaufgerufen wird (wie in { cat > /dev/null; tail; } < file)
Stéphane Chazelas,
4
@StephaneChazelas * nix - die Welt der seltsamen Randfälle wird normal. (Obwohl suchbare und nicht suchbare Eingaben definitiv ein gültiger Punkt sind.)
CVn
69

Du hättest sehen können, wie es tailfunktioniert. Wie Sie für eine meiner Dateien können, readwird dreimal ausgeführt und insgesamt werden ungefähr 10 KByte gelesen:

strace 2>&1  tail ./huge-file >/dev/null  | grep -e "read" -e "lseek" -e "open" -e "close"
open("./huge-file", O_RDONLY)           = 3
lseek(3, 0, SEEK_CUR)                   = 0
lseek(3, 0, SEEK_END)                   = 80552644
lseek(3, 80551936, SEEK_SET)            = 80551936
read(3, ""..., 708) = 708
lseek(3, 80543744, SEEK_SET)            = 80543744
read(3, ""..., 8192) = 8192
read(3, ""..., 708) = 708
close(3)                                = 0
Sergei Kurenkov
quelle
Ich verstehe nicht, wie dies die Frage beantwortet. Können Sie erklären, was hier los ist?
Iain Samuel McLean Elder
10
straceZeigt an, was Systemaufrufe beim Ausführen tailtun. Einige Informationen zu Systemaufrufen finden Sie hier en.wikipedia.org/wiki/System_call . Kurz - öffnen - öffnet eine Datei und gibt ein Handle zurück (3 in diesem Beispiel), lseekPositionen, an denen Sie lesen und readgerade lesen werden, und wie Sie sehen können, gibt es zurück, wie viele Bytes gelesen werden,
Sergei Kurenkov
2
Wenn Sie also Systemaufrufe analysieren, können Sie manchmal verstehen, wie ein Programm funktioniert.
Sergei Kurenkov
26

Da eine Datei möglicherweise auf einer Festplatte verstreut ist, muss sie nacheinander gelesen werden, aber ich verstehe solche Interna nicht gut.

Wie Sie jetzt wissen, tailsucht nur das Ende der Datei (mit dem Systemaufruf lseek) und arbeitet rückwärts. Aber in der oben zitierten Bemerkung fragen Sie sich: "Woher weiß Tail, wo auf der Festplatte das Ende der Datei zu finden ist?"

Die Antwort ist einfach: Schwanz weiß es nicht. Bei Prozessen auf Benutzerebene werden Dateien als kontinuierliche Streams betrachtet, sodass tailnur der Versatz vom Dateianfang bekannt ist. Im Dateisystem ist der "Inode" (Verzeichniseintrag) der Datei jedoch mit einer Liste von Zahlen verknüpft, die den physischen Speicherort der Datenblöcke der Datei angeben. Wenn Sie aus der Datei lesen, ermittelt der Kernel / der Gerätetreiber, welches Teil Sie benötigen, ermittelt seinen Speicherort auf der Festplatte und holt es für Sie.

Dafür haben wir Betriebssysteme: Sie müssen sich also keine Sorgen machen, wo die Blöcke Ihrer Datei verstreut sind.

alexis
quelle
2

Wenn headoder tail scheint , die gesamte Datei zu lesen, ist ein wahrscheinlicher Grund, dass die Datei wenige oder keine Zeilenumbrüche enthält . Ich bin vor ein paar Monaten darüber gestolpert, mit einem sehr großen (Gigabyte) JSON-Blob, der mit keinerlei Leerzeichen serialisiert wurde, nicht einmal in Strings.

Wenn Sie GNU head / tail haben, können Sie -c Ndie ersten / letzten N Bytes anstelle von Zeilen ausgeben, dies ist jedoch leider keine POSIX-Funktion.

zwol
quelle
1

Wie Sie in der Quelltextzeile 525 sehen können, sehen Sie die Kommentare zur Implementierung.

 /* Print the last N_LINES lines from the end of file FD.
   Go backward through the file, reading 'BUFSIZ' bytes at a time (except
   probably the first), until we hit the start of the file or have
   read NUMBER newlines.
   START_POS is the starting position of the read pointer for the file
   associated with FD (may be nonzero).
   END_POS is the file offset of EOF (one larger than offset of last byte).
   Return true if successful.  */
Seenivasan
quelle