Tail legge l'intero file?


113

Se voglio tailun file di testo da 25 GB, il tailcomando legge l'intero file?

Dal momento che un file potrebbe essere sparso su un disco, immagino che debba, ma non capisco bene questi interni.

Risposte:


119

No, tailnon legge l'intero file, cerca fino alla fine, quindi legge i blocchi all'indietro fino a raggiungere il numero previsto di righe, quindi visualizza le righe nella direzione corretta fino alla fine del file e probabilmente continua a monitorare file se -fviene utilizzata l' opzione.

Si noti tuttavia che tailnon ha altra scelta che leggere i dati completi se viene fornito un input non ricercabile, ad esempio durante la lettura da una pipe.

Allo stesso modo, quando viene chiesto di cercare le righe a partire dall'inizio del file, usando la tail -n +linenumbersintassi o tail +linenumberl'opzione non standard quando supportata, taillegge ovviamente l'intero file (a meno che non sia interrotto).


14
Accidenti, troppo in fretta :-). Ecco il codice sorgente pertinente . Stampa le ultime N_LINES righe dalla fine del file FD. Andare indietro nel file, leggendo i byte 'BUFSIZ' alla volta (tranne probabilmente il primo), fino a quando non si preme l'inizio del file o non abbiamo letto NUMBER newline.
Patrick,

1
Inoltre, tail +nleggerà l'intero file - prima per trovare il numero desiderato di newline, quindi per produrre il resto.
SF.

@SF. Anzi, risposta aggiornata.
jlliagre,

4
Si noti che non tutte le tailimplementazioni lo fanno o lo fanno correttamente. Ad esempio busybox 1.21.1 tailè rotto a tale riguardo. Si noti inoltre che il comportamento varia quando si utilizza lo tailstdin e dove lo stdin è un file normale e la posizione iniziale nel file non è all'inizio quando tailviene invocata (come in { cat > /dev/null; tail; } < file)
Stéphane Chazelas,

4
@StephaneChazelas * nix - il mondo dei casi strani che diventano normali. (Anche se gli input di ricerca e non di ricerca sono sicuramente un punto valido.)
un CVn del

69

Avresti potuto vedere come tailfunziona te stesso. Come puoi per uno dei miei file readviene fatto tre volte e in totale vengono letti circa 10K byte:

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

Non vedo come questo risponda alla domanda. Puoi spiegare cosa sta succedendo qui?
Iain Samuel McLean Elder,

10
stracemostra cosa tailfanno le chiamate di sistema quando viene eseguito. Qualche introduzione sulle chiamate di sistema che puoi leggere qui en.wikipedia.org/wiki/System_call . Brevemente - apri - apre un file e restituisce un handle (3 in questo esempio), lseekposizioni in cui stai per leggere e readappena legge e come puoi vedere restituisce quanti byte vengono letti,
Sergei Kurenkov

2
Quindi, analizzando le chiamate di sistema, a volte puoi capire come funziona un programma.
Sergei Kurenkov,

26

Poiché un file potrebbe essere sparso su un disco, immagino che debba [leggere il file in sequenza], ma non capisco bene tali elementi interni.

Come ora sai, tailcerca solo alla fine del file (con la chiamata di sistema lseek) e funziona all'indietro. Ma nell'osservazione sopra citata, ti stai chiedendo "come fa tail a sapere dove sul disco trovare la fine del file?"

La risposta è semplice: la coda non lo sa. I processi a livello di utente vedono i file come flussi continui, quindi tutto ciò che tailpuò sapere è l'offset dall'inizio del file. Ma nel filesystem, l '"inode" (voce della directory) del file è associato a un elenco di numeri che indicano la posizione fisica dei blocchi di dati del file. Quando leggi dal file, il kernel / il driver del dispositivo scoprono quale parte ti serve, determina la sua posizione sul disco e la recupera per te.

Questo è il tipo di cosa per cui abbiamo i sistemi operativi: quindi non devi preoccuparti di dove sono sparsi i blocchi del tuo file.


2

Se heado tail sembra che stia leggendo l'intero file, un probabile motivo è che il file contiene pochi o nessun carattere di nuova riga . L'ho inciampato qualche mese fa con un blob JSON molto grande (gigabyte) che era stato serializzato senza spazi bianchi, nemmeno nelle stringhe.

Se hai GNU head / tail puoi usare -c Nper stampare il primo / ultimo N byte anziché le righe , ma sfortunatamente questa non è una funzione POSIX.


1

Come puoi vedere nella riga di codice 525, puoi vedere i commenti per l'implementazione.

 /* 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.  */
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.