web-dev-qa-db-ja.com

tailはファイル全体を読み取りますか?

25 GBのテキストファイルをtailしたい場合、tailコマンドはファイル全体を読み取りますか?

ファイルはディスク上に散らばっているかもしれないので、そうする必要があると思いますが、そのような内部についてはよくわかりません。

114
The Unfun Cat

いいえ、tailはファイル全体を読み取るのではなく、最後までシークし、予想される行数に達するまでブロックを逆方向に読み取り、ファイルの終わりまで適切な方向に行を表示します、および-fオプションが使用されている場合は、ファイルの監視を継続します。

ただし、パイプから読み取る場合など、シークできない入力が提供された場合、tailにはデータ全体を読み取る以外に選択肢がないことに注意してください。

同様に、tail -n +linenumber構文またはtail +linenumber非標準オプションがサポートされている場合にtailを使用すると、ファイルの先頭から始まる行を検索するように求められた場合、ファイル全体を読み取ります(ただし、中断された)。

120
jlliagre

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
70
user17530

ファイルがディスク上に散在している可能性があるので、[ファイルを順番に読み取る]必要があると思いますが、そのような内部についてはよくわかりません。

ご存じのように、tailはファイルの終わりまでシークし(システムコールlseekを使用)、逆方向に動作します。しかし、上記のコメントでは、"tailがディスク上のどこでファイルの終わりを見つけるのかをどのように知るのですか?"

答えは簡単です。テールは知りません。ユーザーレベルのプロセスは、ファイルを連続したストリームとして認識しているため、tailが認識できるのは、ファイルの先頭からのオフセットだけです。しかし、ファイルシステムでは、ファイルの「iノード」(ディレクトリエントリ)は、ファイルのデータブロックの物理的な場所を示す番号のリストに関連付けられています。ファイルから読み取ると、カーネル/デバイスドライバーは必要な部分を見つけ出し、ディスク上のその場所を計算して、それをフェッチします。

これは、オペレーティングシステムの一種です。そのため、ファイルのブロックがどこに分散しているかについて心配する必要はありません。

26
alexis

headまたはtailappearsがファイル全体を読み取る場合、考えられる理由はファイルに含まれる改行文字がほとんどまたはまったくないであると考えられます。数か月前に、文字列でさえも空白を一切含まずにシリアル化された非常に大きな(ギガバイト)JSON blobを使用して、これを試しました。

GNU head/tailがある場合、-c N最初の/最後のN byteslinesの代わりに出力しますが、残念ながらこれはPOSIX機能ではありません。

2
zwol

source code 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.  */
1
Seenivasan