回答:
いいえ、tail
ファイル全体を読み取らず、最後までシークし、予想される行数に達するまでブロックを逆方向に読み取り、ファイルの最後まで適切な方向に行を表示します。-f
オプションを使用する場合はファイル。
ただしtail
、パイプから読み取る場合など、シークできない入力が提供された場合、データ全体を読み取る以外に選択肢がないことに注意してください。
同様に、サポートされている場合にtail -n +linenumber
構文またはtail +linenumber
非標準オプションを使用して、ファイルの先頭から始まる行を検索するように求められた場合、tail
明らかにファイル全体が読み取られます(中断されない限り)。
tail +n
ファイル全体を読み取ります-最初に必要な数の改行を見つけ、次に残りを出力します。
tail
実装がそれを行うわけではないことに注意してください。たとえば、busybox 1.21.1 tail
はその点で壊れています。また、ときの挙動が変化することに注意してtail
stdinとどこ標準入力が通常のファイルであり、ファイル内の初期位置が先頭にないINGのtail
(のように呼び出されたが{ cat > /dev/null; tail; } < file
)
あなたtail
自身がどのように機能するかを見ることができたでしょう。私のファイルの1つでread
3回行われ、合計で約10Kバイトが読み取られます:
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
tail
実行時にシステムコールが何をするかを示します。ここでen.wikipedia.org/wiki/System_callを読むことができるシステムコールに関するいくつかの紹介。簡単に言えば-オープン-ファイルを開き、ハンドル(この例では3)、lseek
読み取りを行うread
位置と読み取りだけを返します。また、
ファイルはディスク上に散らばっているかもしれないので、[ファイルを順番に読む]必要があると思いますが、そのような内部構造をよく理解していません。
ご存知のようtail
に、ファイルの最後まで(システムコールでlseek
)シークし、逆方向に動作します。しかし、上記の発言では、「ファイルの終わりを見つけるためにディスク上のどこをtailがどのように知るのでしょうか?」
答えは簡単です。テールは知りません。ユーザーレベルのプロセスは、ファイルを連続ストリームと見なしtail
ます。そのため、ファイルの先頭からのオフセットのみを知ることができます。ただし、ファイルシステムでは、ファイルの「inode」(ディレクトリエントリ)は、ファイルのデータブロックの物理的な場所を示す番号のリストに関連付けられています。ファイルから読み取ると、カーネル/デバイスドライバーが必要な部分を特定し、ディスク上のその場所を特定し、それを取得します。
それは私たちがオペレーティングシステムを持っているようなものです:あなたのファイルのブロックがどこに散らばっているのかを心配する必要はありません。
あなたが見ることができるようにソースコードの行525は、実装のためのコメントを見ることができます。
/* 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. */