web-dev-qa-db-ja.com

「tail -f ... | tail」が出力を生成できないのはなぜですか?

次のコマンドで出力が生成されないのはなぜですか?

$ tail -f /etc/passwd | tail

buffering について読んだ後、次のことを試してみましたが、役に立ちませんでした:

$ tail -f /etc/passwd | stdbuf -oL tail

以下は出力を生成することに注意してください。

$ tail /etc/passwd | tail

これもそうです:

$ tail -f /etc/passwd | head

私はテールバージョン8.21(GNU coreutils)を使用しています。

36
thomie

UNIXですべてを見たと思った。この質問は私を独りぼっちから落とした。すばらしい質問ですね。

tailは、最後のX行を示します。 tail -fも同じですが、基本的には無限ループです。起動時に、ファイルの最後のX行を表示し、OSのマジック(inotifyなど)を使用して監視し、新しい行を表示します。

tailがファイルの終わりを見つけられる必要があります。tailが"last"は未定義であるため、ファイルの最後では、最後のX行を表示できません。この場合、tailは何をするのでしょうか?ファイルの終わりが見つかるまで待機します。

このことを考慮:

$ chatter() { while :; do date; sleep 1; done; }
$ chatter | tail -f

chatterからの明確なファイルの終わりは決してないので、これは進歩するようには見えません。

tailにファイルシステムパイプの最後の行を提供するように要求した場合も、同じ動作が得られます。考慮してください:

$ mkfifo test.pipe
$ tail test.pipe

認識された問題を回避するためのstdbufは高貴な試みでした。ただし、重要な事実は、I/Oバッファリングが根本的な原因ではないことです。明確なファイルの終わりがないことが原因です。 tail.cソースコード をチェックアウトすると、file_lines関数のコメントが次のように表示されます。

END_POSは、EOF(最後のバイトのオフセットよりも1つ大きい)のファイルオフセットです。

それが魔法です。あらゆる構成で機能するには、tailのファイルの終わりが必要です。 headにはそのような制限はありません。ファイルの開始が必要なだけです(これにはない場合があります。head test.pipeを試してください)。 sedawkのようなストリーム指向のツールは、ファイルの最初または最後を必要としません。これらはバッファで機能します。

15
bishop

tail -fの尻尾は現在のところ実際には不明なものなので、次のtailはどのようにそれを知る必要がありますか。一方、tail -fの頭はすでに知られているため、処理することができます。

または、もっと簡単に言えば、tailはファイルの終わりを基準にしていますが、tail -fの出力ストリームはEOF(少なくとも終了前ではありません) )。

最初のtailのpidを見つけてそれをkillする場合は、then 2番目の出力を確認してください。

37
Ghanima

技術的な答え

入力としてストリームを使用して実行している場合、tailはストリームを読み取るときに満たすn- lineバッファーを保持しますが、ストリームの最後に到達するまでこれらの行を出力できません。入力ストリームから読み取ろうとすると、特別なEOFコードを受け取ります。呼び出しtail -fは終了しないため、ストリームを閉じることはありません。そのストリームの最後の10行を返します。

21
sleblanc

tailの機能は、入力またはファイルの最後の部分(「テール」)を表示することです。 (オプション -fは後で何をするかということなので、ここでは関係ありません。)

ファイルについて考えてみましょう:

ファイルの最後の部分とは何ですか?
ファイルの最後のn行だとしましょう。

入力ファイルの行iを読み取るときに、印刷する必要があるかどうかをどのように判断するのですか?
それが最後の部分にあるかどうかはわかりません-最終行がどちらになるかわからないためです。それでできません今すぐ印刷します。

最後のn行の一部であることが明らかになるまで、またはnをさらに知っているため、もはやその行の一部でなくなることができるまで行を保持する必要があります線

ファイルの終わりに到達すると、最後に保持したn行が実際にファイルの最後のn行であることがわかります。

さて、の場合

tail -f /etc/passwd | tail

最初のtailはファイルを読み取り、それからさらにデータを取得するを待って、それも書き込みます。つまり、読み取るファイルの終わりになると、ファイルの終わりを知らせないが2番目の末尾に追加されます。それがなければ、ファイルの終わりの2番目のtail通知されないなので、出力できる最後の行である決してわかりませんです。

3
Volker Siegel