Apakah ekor membaca seluruh file?

113

Jika saya ingin tailfilefile 25 GB, apakah tailperintah membaca seluruh file?

Karena file mungkin tersebar di disk saya bayangkan itu harus, tetapi saya tidak mengerti internal seperti itu dengan baik.

Kucing Unfun
sumber

Jawaban:

119

Tidak, tailtidak membaca keseluruhan file, ia mencari sampai akhir lalu membaca blok ke belakang sampai jumlah garis yang diharapkan telah tercapai, kemudian menampilkan garis dalam arah yang benar sampai akhir file, dan mungkin tetap memantau file jika -fopsi digunakan.

Namun perhatikan bahwa tailtidak ada pilihan selain membaca seluruh data jika memberikan input yang tidak dapat dicari, misalnya saat membaca dari sebuah pipa.

Demikian pula, ketika diminta untuk mencari baris mulai dari awal file, dengan menggunakan tail -n +linenumbersintaks atau tail +linenumberopsi non-standar ketika didukung, tailjelas membaca seluruh file (kecuali terganggu).

Jlliagre
sumber
14
Sial, terlalu cepat :-). Berikut kode sumber yang relevan . Cetak baris N_LINES terakhir dari akhir file FD. Pergi mundur melalui file, membaca byte 'BUFSIZ' pada suatu waktu (kecuali mungkin yang pertama), sampai kita menekan awal file atau telah membaca NUMBER baris baru.
Patrick
1
Juga, tail +nakan membaca seluruh file - pertama untuk menemukan jumlah baris baru yang diinginkan, kemudian untuk mengeluarkan sisanya.
SF.
@ SF. Memang, jawaban diperbarui.
jlliagre
4
Perhatikan bahwa tidak semua tailimplementasi melakukannya atau melakukannya dengan benar. Misalnya busybox 1.21.1 tailrusak dalam hal itu. Perhatikan juga bahwa perilaku bervariasi ketika menggunakan tailstdin dan di mana stdin adalah file biasa dan posisi awal dalam file tidak di awal ketika taildipanggil (seperti di { cat > /dev/null; tail; } < file)
Stéphane Chazelas
4
@StephaneChazelas * nix - dunia kasus tepi aneh menjadi normal. (Meskipun input yang dapat dicari vs yang tidak dapat dicari jelas merupakan poin yang valid.)
CVn
69

Anda bisa melihat cara tailkerjanya sendiri. Yang Anda bisa untuk salah satu file saya readdilakukan tiga kali dan total sekitar 10K byte dibaca:

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
sumber
Saya tidak melihat bagaimana ini menjawab pertanyaan. Bisakah Anda jelaskan apa yang terjadi di sini?
Iain Samuel McLean Penatua
10
stracemenunjukkan apa yang taildilakukan panggilan sistem saat dijalankan. Beberapa pengantar tentang panggilan sistem dapat Anda baca di sini en.wikipedia.org/wiki/System_call . Secara singkat - buka - membuka file dan mengembalikan pegangan (3 dalam contoh ini), lseekposisi di mana Anda akan membaca dan readhanya membaca dan karena Anda dapat melihatnya mengembalikan berapa byte yang dibaca,
Sergei Kurenkov
2
Jadi, menganalisis panggilan sistem kadang-kadang Anda bisa memahami cara kerja suatu program.
Sergei Kurenkov
26

Karena file mungkin tersebar di disk saya bayangkan itu harus [membaca file secara berurutan], tapi saya tidak mengerti internal seperti itu dengan baik.

Seperti yang Anda ketahui, tailhanya mencari ke akhir file (dengan panggilan sistem lseek), dan bekerja mundur. Tetapi dalam komentar yang dikutip di atas, Anda bertanya-tanya "bagaimana ekor tahu di mana pada disk untuk menemukan akhir file?"

Jawabannya sederhana: Ekor tidak tahu. Proses tingkat pengguna melihat file sebagai aliran kontinu, sehingga yang tailbisa diketahui adalah offset dari awal file. Tetapi dalam sistem file, "inode" file (entri direktori) dikaitkan dengan daftar angka yang menunjukkan lokasi fisik blok data file. Ketika Anda membaca dari file, kernel / driver perangkat mencari tahu bagian mana yang Anda butuhkan, menentukan lokasinya pada disk dan mengambilnya untuk Anda.

Itulah jenis sistem operasi yang kami miliki: jadi Anda tidak perlu khawatir tentang di mana blok file Anda tersebar.

alexis
sumber
2

Jika headatau tail tampaknya membaca seluruh file, kemungkinan alasannya adalah bahwa file tersebut berisi sedikit atau tidak ada karakter baris baru . Saya tersandung ini beberapa bulan yang lalu dengan gumpalan JSON yang sangat besar (gigabytes) yang telah diserialkan tanpa spasi apa pun, bahkan dalam string.

Jika Anda memiliki GNU head / tail yang dapat Anda gunakan -c Nuntuk mencetak byte pertama / terakhir alih-alih garis , tapi sayangnya ini bukan fitur POSIX.

zwol
sumber
1

Seperti yang Anda lihat di baris kode sumber 525, Anda dapat melihat komentar untuk implementasi.

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