Réponses:
Non, tailne 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' -foption est utilisée.
Notez cependant que tailn’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 +linenumbersyntaxe ou de tail +linenumberl'option non standard lorsque pris en charge, taillit intégralement le fichier (sauf si interrompu).
tail +nlira l’ensemble du fichier - d’abord pour trouver le nombre souhaité de nouvelles lignes, puis pour afficher le reste.
tailimplémentations ne le font pas ou ne le font pas correctement. Par exemple, busybox 1.21.1 tailest cassé à cet égard. Notez également que le comportement varie lorsque tailstdin 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 tailest invoquée (comme dans { cat > /dev/null; tail; } < file)
Vous auriez pu voir comment ça tailmarche vous-même. Comme vous pouvez le faire pour un de mes fichiers readest 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
stracemontre ce que tailfont 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 lseekpositions où vous allez lire et readsimplement 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, tailcherche 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 tailpeut ê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 headou 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 Npour 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. */