Jika saya ingin tail
filefile 25 GB, apakah tail
perintah membaca seluruh file?
Karena file mungkin tersebar di disk saya bayangkan itu harus, tetapi saya tidak mengerti internal seperti itu dengan baik.
Jika saya ingin tail
filefile 25 GB, apakah tail
perintah membaca seluruh file?
Karena file mungkin tersebar di disk saya bayangkan itu harus, tetapi saya tidak mengerti internal seperti itu dengan baik.
Jawaban:
Tidak, tail
tidak 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 -f
opsi digunakan.
Namun perhatikan bahwa tail
tidak 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 +linenumber
sintaks atau tail +linenumber
opsi non-standar ketika didukung, tail
jelas membaca seluruh file (kecuali terganggu).
tail +n
akan membaca seluruh file - pertama untuk menemukan jumlah baris baru yang diinginkan, kemudian untuk mengeluarkan sisanya.
tail
implementasi melakukannya atau melakukannya dengan benar. Misalnya busybox 1.21.1 tail
rusak dalam hal itu. Perhatikan juga bahwa perilaku bervariasi ketika menggunakan tail
stdin dan di mana stdin adalah file biasa dan posisi awal dalam file tidak di awal ketika tail
dipanggil (seperti di { cat > /dev/null; tail; } < file
)
Anda bisa melihat cara tail
kerjanya sendiri. Yang Anda bisa untuk salah satu file saya read
dilakukan 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
strace
menunjukkan apa yang tail
dilakukan 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), lseek
posisi di mana Anda akan membaca dan read
hanya membaca dan karena Anda dapat melihatnya mengembalikan berapa byte yang dibaca,
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, tail
hanya 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 tail
bisa 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.
Jika head
atau 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 N
untuk mencetak byte pertama / terakhir alih-alih garis , tapi sayangnya ini bukan fitur POSIX.
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. */