¿La cola lee todo el archivo?

113

Si quiero tailun tailarchivo de texto de 25 GB, ¿el comando lee todo el archivo?

Dado que un archivo puede estar disperso en un disco, imagino que tiene que hacerlo, pero no entiendo bien esas cosas internas.

El gato no divertido
fuente

Respuestas:

119

No, tailno lee todo el archivo, busca hasta el final, luego lee los bloques hacia atrás hasta que se haya alcanzado el número esperado de líneas, luego muestra las líneas en la dirección correcta hasta el final del archivo y posiblemente permanece monitoreando el archivo si -fse usa la opción.

Sin embargo, tailtenga en cuenta que no tiene más remedio que leer todos los datos si se proporciona una entrada no buscable, por ejemplo, al leer desde una tubería.

Del mismo modo, cuando se le pide que busque líneas que comienzan desde el principio del archivo, con el uso de la tail -n +linenumbersintaxis o tail +linenumberla opción no estándar cuando es compatible, tailobviamente lee todo el archivo (a menos que se interrumpa).

jlliagre
fuente
14
Maldición, demasiado rápido :-). Aquí está el código fuente relevante . Imprima las últimas líneas N_LINES desde el final del archivo FD. Retroceda a través del archivo, leyendo bytes 'BUFSIZ' a la vez (excepto probablemente el primero), hasta que lleguemos al inicio del archivo o leamos NUMBER líneas nuevas.
Patrick
1
Además, tail +nleerá todo el archivo, primero para encontrar el número deseado de nuevas líneas, luego para generar el resto.
SF.
@SF. De hecho, la respuesta actualizada.
jlliagre
44
Tenga en cuenta que no todas las tailimplementaciones lo hacen o lo hacen correctamente. Por ejemplo, busybox 1.21.1 tailestá roto en ese sentido. También tenga en cuenta que el comportamiento varía cuando tailing stdin y donde stdin es un archivo normal y la posición inicial en el archivo no es al principio cuando tailse invoca (como en { cat > /dev/null; tail; } < file)
Stéphane Chazelas
44
@StephaneChazelas * nix: el mundo de los casos extraños se está volviendo normal. (Aunque las entradas buscables versus no buscables son definitivamente un punto válido.)
un CVn el
69

Podrías haber visto cómo tailfunciona tú mismo. Como puede, uno de mis archivos readse realiza tres veces y en total se leen aproximadamente 10K bytes:

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
fuente
No veo cómo esto responde la pregunta. ¿Puedes explicar lo que está pasando aquí?
Iain Samuel McLean Élder
10
stracemuestra qué tailhacen las llamadas al sistema cuando se ejecuta. Alguna introducción sobre las llamadas al sistema que puede leer aquí en.wikipedia.org/wiki/System_call . Brevemente - abrir - abre un archivo y devuelve un identificador (3 en este ejemplo), lseekposiciones donde va a leer y readsolo lee y, como puede ver, devuelve cuántos bytes se leen,
Sergei Kurenkov
2
Entonces, al analizar las llamadas del sistema, a veces puede comprender cómo funciona un programa.
Sergei Kurenkov
26

Dado que un archivo puede estar disperso en un disco, imagino que tiene que [leer el archivo secuencialmente], pero no entiendo bien esas partes internas.

Como ya sabe, tailsolo busca el final del archivo (con la llamada al sistema lseek) y funciona al revés. Pero en el comentario citado anteriormente, se pregunta "¿cómo sabe la cola dónde en el disco encontrar el final del archivo?"

La respuesta es simple: Tail no lo sabe. Los procesos a nivel de usuario ven los archivos como flujos continuos, por lo que todo lo que se tailpuede saber es el desplazamiento desde el inicio del archivo. Pero en el sistema de archivos, el "inodo" del archivo (entrada de directorio) está asociado con una lista de números que denotan la ubicación física de los bloques de datos del archivo. Cuando lees el archivo, el núcleo / el controlador del dispositivo descubre qué parte necesitas, calcula su ubicación en el disco y la busca por ti.

Ese es el tipo de cosas para las que tenemos sistemas operativos: para que no tenga que preocuparse por dónde están dispersos los bloques de sus archivos.

alexis
fuente
2

Si heado tail parece estar leyendo el archivo completo, una razón probable es que el archivo contiene pocos o ningún carácter de nueva línea . Me tropecé con esto hace unos meses con un blob JSON muy grande (gigabytes) que se había serializado sin espacios en blanco, ni siquiera en cadenas.

Si tiene GNU head / tail puede usar -c Npara imprimir el primer / último N bytes en lugar de líneas , pero desafortunadamente esta no es una característica POSIX.

zwol
fuente
1

Como puede ver en la línea de código fuente 525, puede ver los comentarios para la implementación.

 /* 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
fuente