Réponses:
Non, tail
ne lit pas tout le fichier, il cherche la fin puis lit les blocs à l'envers jusqu'à atteindre le nombre de lignes attendu, puis affiche les lignes dans le bon sens jusqu'à la fin du fichier et reste éventuellement en veille. fichier si l' -f
option est utilisée.
Notez cependant que tail
n’a pas d’autre choix que de lire l’ensemble des données si une entrée non recherchée est fournie, par exemple lors de la lecture d’un canal.
De même, lorsqu'on lui demande de rechercher des lignes à partir du début du fichier, avec l'aide de la tail -n +linenumber
syntaxe ou de tail +linenumber
l'option non standard lorsque pris en charge, tail
lit intégralement le fichier (sauf si interrompu).
tail +n
lira l’ensemble du fichier - d’abord pour trouver le nombre souhaité de nouvelles lignes, puis pour afficher le reste.
tail
implémentations ne le font pas ou ne le font pas correctement. Par exemple, busybox 1.21.1 tail
est cassé à cet égard. Notez également que le comportement varie lorsque tail
stdin est utilisé et que stdin est un fichier normal et que la position initiale dans le fichier n’est pas au début lorsqu’elle tail
est invoquée (comme dans { cat > /dev/null; tail; } < file
)
Vous auriez pu voir comment ça tail
marche vous-même. Comme vous pouvez le faire pour un de mes fichiers read
est fait trois fois et au total environ 10K octets sont lus:
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
strace
montre ce que tail
font les appels système lors de l'exécution. Vous pouvez lire un peu d’introduction sur les appels système en.wikipedia.org/wiki/System_call . En bref - ouvrir - ouvre un fichier et retourne un descripteur (3 dans cet exemple), les lseek
positions où vous allez lire et read
simplement lire et comme vous pouvez le voir, combien d'octets lus sont lus,
Puisqu'un fichier peut être dispersé sur un disque, j'imagine qu'il doit [lire le fichier séquentiellement], mais je ne comprends pas bien ces éléments internes.
Comme vous le savez maintenant, tail
cherche simplement la fin du fichier (avec l'appel système lseek
), et fonctionne à l'envers. Mais dans la remarque citée ci-dessus, vous vous demandez "comment tail ne sait où sur le disque trouver la fin du fichier?"
La réponse est simple: la queue ne sait pas. Les processus au niveau utilisateur voient les fichiers comme des flux continus, de sorte que tout tail
peut être connu, c'est le décalage par rapport au début du fichier. Mais dans le système de fichiers, "l'inode" du fichier (entrée de répertoire) est associé à une liste de nombres indiquant l'emplacement physique des blocs de données du fichier. Lorsque vous lisez le fichier, le noyau / le pilote de périphérique détermine la partie dont vous avez besoin, détermine son emplacement sur le disque et le recherche à votre place.
C'est le genre de chose pour laquelle nous avons un système d'exploitation: vous n'avez donc pas à vous soucier de la répartition des blocs de votre fichier.
Si head
ou tail
semble lire tout le fichier, cela tient probablement au fait que le fichier contient peu ou pas de caractères de nouvelle ligne . J'y ai trébuché il y a quelques mois avec un très gros blob JSON (sérialisé) sérialisé sans aucun espace, même pas dans des chaînes.
Si vous avez une tête / queue GNU, vous pouvez utiliser -c N
pour imprimer le premier / dernier N octets au lieu de lignes , mais malheureusement, ce n’est pas une fonctionnalité POSIX.
Comme vous pouvez le voir dans la ligne de code source 525, vous pouvez voir les commentaires pour l'implémentation.
/* 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. */