名前付きパイプを読む:tailまたはcat?

名前付きパイプを読む:tailまたはcat?

以下を使用してファイル記述子を作成しました。

mkfifo fifo

このパイプに何かが書かれたら、再利用したいです。まもなく。私は使うべきですか?

tail -f fifo

または

while true; do cat fifo; done

彼らは同じことをしているようで、パフォーマンスの違いを測定することはできません。ただし、システムがinotify(Busyboxなど)をサポートしていない場合は、前者を次のように設定する必要があります。

tail -f -s 0 fifo

mkfifo fifo && busybox tail -f -s 0 fifo & echo hi>fifoただし、これはCPU使用率が100%です(/cancelfg 1およびでテストCtrlC)。もしそうなら、while-true-catはより信頼性の高いソリューションですか?

答え1

これを行うとき:

cat fifo

fifoすでに書き込み用に開いている他のプロセスがないと仮定すると、システムコールがcatブロックされますopen()。他のプロセスが書き込み用にファイルを開くと、パイプはインスタンス化されてopen()返されます。ループが呼び出され、他のプロセスがパイプにデータを書き込むまでブロックされますcatread()read()

catファイル終了文字は、他のすべての書き込みプロセスがファイル記述子を閉じたときに表示されますfifo。これがcat終了し、パイプラインが破壊されます。

cat後で作成した内容を読み取るには、もう一度実行する必要がありますfifo(ただし、他のパイプインスタンスを介して)。

存在する:

tail -f file

同様に、プロセスが書き込み用にファイルを開くのを待ちますcat。ところで、ここでは最初からコピーをtail指定しなかったので、最後の10行が何かを調べるにはeofまで待たなければならないため、書き込みが終わるまで何も見えません。-n +1tail

その後、tail対応するfdはパイプに対して閉じられません。これは、パイプインスタンスが破壊されず、毎秒パイプから読み取ろうとすることを意味します(Linuxでは、inotify一部のバージョンのGNUを使用してポーリングを防ぐことができますtail)。これは、他のプロセスが書き換えるためにファイルを開くまでeof(即時100%CPUが表示される理由です(GNUの場合は1秒待つのではなくs間を待たないことを意味します))read()を返します。-s 0tailread()

代わりにここでを使用したいかもしれませんが、catインスタンス化後にパイプインスタンスが常に近くに残っていることを確認してください。これを行うには、ほとんどのシステムで次のことができます。

cat 0<> fifo # the 0 is needed for recent versions of ksh93 where the
             # default fd changed from 0 to 1 for the <> operator

catstdin は読み書き用に開いています。つまり、cateofは決して表示されません(fifo他のプロセスが書き込み用にパイプを開かなくてもすぐにパイプをインスタンス化します)。

これが機能しないシステムでは、次のことができます。

cat < fifo 3> fifo

これにより、他のプロセスが書き込み用に開かれると、最初の読み取りfifo専用が返されますopen()。この時点で、シェルはopen()開始前に書き込み専用を実行しcatてパイプが再び切断されるのを防ぎます。

要約すると、次のようになります。

  • 対照的にcat file、最初のラウンド以降は停止しません。
  • 比較するとtail -n +1 -f file、最初のラウンドの後はread()毎秒役に立たないタスクを実行せず、パイプの1つのインスタンスにはeofがなく、2番目のプロセスが書き込み用にパイプを開かなかった後に遅延があります。最大1秒。最初はそれを閉じました。
  • と比較してtail -f file。上記に加えて、何かを出力する前に最初のラウンドが終わるまで待つ必要はありません(最後の10行のみ)。
  • ループとは異なり、cat fileパイプインスタンスは1つだけです。 1で述べた競合ウィンドウは防止されます。

read()1この時点で、eofの最後の表現とcatパイプの読み取りの終わりが終了して閉じるまでの間に、実際にプロセスが書き込みのfifoためにパイプを再度開くことができる小さなウィンドウがあります。まだ読んだ内容があります。 Take the end).その後cat、終了後に他のプロセスが読み取りプロセスを開く前にfifo何かを書くと、SIGPIPEによって終了します。

答え2

別の解決策を提案します。 2番目の最後に書き込むプロセスがある限り、パイプを読み取ることができます。したがって、catバックグラウンド(または他の端末)から偽を作成できます。たとえば、次のようになります。

mkfifo fifo
cat >fifo &
cat fifo

これで必要に応じてfifoに書き込むことができ、完了したら現在のプロセス終了を使用してcatからC-c最初にバックグラウンドで開始fgし、最後に停止します。catC-d

関連情報