Se voglio tail
un file di testo da 25 GB, il tail
comando legge l'intero file?
Dal momento che un file potrebbe essere sparso su un disco, immagino che debba, ma non capisco bene questi interni.
Se voglio tail
un file di testo da 25 GB, il tail
comando 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:
No, tail
non 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 -f
viene utilizzata l' opzione.
Si noti tuttavia che tail
non 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 +linenumber
sintassi o tail +linenumber
l'opzione non standard quando supportata, tail
legge ovviamente l'intero file (a meno che non sia interrotto).
tail +n
leggerà l'intero file - prima per trovare il numero desiderato di newline, quindi per produrre il resto.
tail
implementazioni 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 tail
stdin e dove lo stdin è un file normale e la posizione iniziale nel file non è all'inizio quando tail
viene invocata (come in { cat > /dev/null; tail; } < file
)
Avresti potuto vedere come tail
funziona te stesso. Come puoi per uno dei miei file read
viene 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
strace
mostra cosa tail
fanno 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), lseek
posizioni in cui stai per leggere e read
appena legge e come puoi vedere restituisce quanti byte vengono letti,
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, tail
cerca 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 tail
può 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.
Se head
o 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 N
per stampare il primo / ultimo N byte anziché le righe , ma sfortunatamente questa non è una funzione POSIX.
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. */