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


113

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

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

回答:


119

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

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

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


14
くそー、速すぎる:-)。関連するソースコードは次のとおりですファイルFDの最後から最後のN_LINES行を印刷します。ファイルの先頭に到達するか、またはNUMBER個の改行を読み取るまで、一度に(おそらく最初のバイトを除く)バイトを読み取って、ファイルを逆方向​​に移動します。
パトリック

1
また、tail +nファイル全体を読み取ります-最初に必要な数の改行を見つけ、次に残りを出力します。
SF。

@SF。確かに、回答が更新されました。
jlliagre

4
すべてのtail実装がそれを行うわけではないことに注意してください。たとえば、busybox 1.21.1 tailはその点で壊れています。また、ときの挙動が変化することに注意してtailstdinとどこ標準入力が通常のファイルであり、ファイル内の初期位置が先頭にないINGのtail(のように呼び出されたが{ cat > /dev/null; tail; } < file
ステファンChazelas

4
@StephaneChazelas * nix-奇妙なエッジケースが正常になっている世界。(シーク可能な入力とシークできない入力は間違いなく有効なポイントです。)
CVn

69

あなたtail自身がどのように機能するかを見ることができたでしょう。私のファイルの1つでread3回行われ、合計で約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

これがどのように質問に答えているかわかりません。ここで何が起こっているのか説明できますか?
イアン・サミュエル・マクリーン長老

10
stracetail実行時にシステムコールが何をするかを示します。ここでen.wikipedia.org/wiki/System_callを読むことができるシステムコールに関するいくつかの紹介。簡単に言えば-オープン-ファイルを開き、ハンドル(この例では3)、lseek読み取りを行うread位置と読み取りだけを返します。また、
ご覧のとおり

2
したがって、システムコールを分析すると、プログラムの動作を理解できる場合があります。
セルゲイキュレンコフ

26

ファイルはディスク上に散らばっているかもしれないので、[ファイルを順番に読む]必要があると思いますが、そのような内部構造をよく理解していません。

ご存知のようtailに、ファイルの最後まで(システムコールでlseek)シークし、逆方向に動作します。しかし、上記の発言では、「ファイルの終わりを見つけるためにディスク上のどこをtailがどのように知るのでしょうか?」

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

それは私たちがオペレーティングシステムを持っているようなものです:あなたのファイルのブロックがどこに散らばっているのかを心配する必要はありません。


2

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

GNU head / tailがある場合、linesの代わりに-c N最初/最後のN バイトを印刷するために使用できますが、残念ながらこれはPOSIX機能ではありません。


1

あなたが見ることができるようにソースコードの行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.  */
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.