mkfifo のあまり書かれていない特徴 ― 2012年08月17日 15時32分21秒
mkfifo
は UNIX のシステムコールであり、UNIX コマンドの一つでもある。FIFO は First-In First-Out で先入れ先出し。データ構造などでは Queue、キューと呼ばれる。UNIX 上では名前付き pipe などとも言われる。
mkfifo でファイルを作成。tail で読み出す。
term1 % mkfifo /tmp/fifo
term1 % tail -f /tmp/fifo
もう一つのターミナルで入力する。
term2 % echo 1 > /tmp/fifo
term2 % echo 2 > /tmp/fifo
そうすると先程の tail が出力をだす。
term1 % mkfifo /tmp/fifo
term1 % tail -f /tmp/fifo
1
2
^C
fifo には幾つかの特徴がある。
まず、open が書き込み側と読み出し側が open を呼ぶまでブロックされる。echo と tail ではなく、両方で cat を使うとその動作が良く解る。読み出し cat を先に起動しても、書き込み cat が始まるまで、待ち続ける。逆もまた然り。
そして、fifo は何度でも使い直す事ができる。cat の実験は同じfifo を用いて何度でもできる。
また、出力側が close をすると、read は 0 を返すことになる。そのため、cat はすぐに終了。select 等や再 open 等で、読み出しの状態を調べる tail -f は、読み出し続ける事になる。
最後に、書き込み側も読み出し側も複数が行なえる。複数のプロセスでの読み出しは、各入力は一つのプロセスにしか渡らない。しかし、close は全てに伝達されてしまうので、一気に全てのプロセスの read が 0 を返す。ほとんど、使い様の無い形だろう。複数の書き込みプロセスが各々書き込んで、一つのプロセスで処理は利用できる。書き込んだ順番と内容は保護されるが、内容は行単位で独立していないと処理しづらい。
この性質を利用して、大量の圧縮ファイルを復元せずに、同時に伸長しつつ、全てを一気にに grep 等といった使い方ができる。
% sh -c 'for i in /var/log/messages*bz2; do bzip2 -d -c $i > /tmp/fifo & done'
% grep da /tmp/fifo
Aug 17 01:09:25 kernel: da0 at umass-sim0 bus 0 scbus0 target 0 lun 0
Aug 17 01:09:25 kernel: da0: <IC25N040 ATCS05-0 0811> Fixed Direct Access SCSI-0 device
Aug 17 01:09:25 kernel: da0: 40.000MB/s transfers
Aug 17 01:09:25 kernel: da0: 38154MB (78140160 512 byte sectors: 255H 63S/T 4864C)
まあ、伸長したので正しく改行が行なわれているとは限らないが、あくまで使い方の一例として。
コメント
_ if ― 2012年08月28日 22時17分16秒
_ uyota ― 2012年08月29日 12時35分15秒
今回の例は、こんなことも出来ますという程度です。
※メールアドレスとURLの入力は必須ではありません。 入力されたメールアドレスは記事に反映されず、ブログの管理者のみが参照できます。
※なお、送られたコメントはブログの管理者が確認するまで公開されません。
トラックバック
このエントリのトラックバックURL: http://uyota.asablo.jp/blog/2012/08/17/6544850/tb
※なお、送られたトラックバックはブログの管理者が確認するまで公開されません。
あまり知らなかった mkfifo のことがわかってようございました。
しかし、最後の grep の例ですが
for i in /var/log/messages*bz2; do bzip2 -dc $i & done | grep da
でいいのではないでしょうか?
シェルプログラミングのパイプで出来ることにわざわざ mkfifo 使う理由はないと思います。
mkfifo が必要になるのは、パイプのように一本道でできない事、
たとえば多段パイプで途中の出力を tee(1) で分岐し、
分岐した先を同じパイプに属する(あるいは属さない)別のプログラムに食わせるといった場合などではないでしょうか?