1
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

入出力が2系統以上あるコマンドを名前付きパイプで繋ぐ

Last updated at Posted at 2017-12-22

中間ファイルを作らないために

複数のコマンドをパイプで繋ぐのはよくやるけど、

$ command1 | command2

入出力が2つ以上あるコマンドを同じように繋げたい場合はどうしたらいいだろうか?

$ command1 -out1 output1 -out2 output2
$ command2 -in1 output1 -in2 output2

名前付きパイプを使う

mkfifoコマンドを使うと名前付きパイプという特殊ファイルを作成できる。
こちらの記事が分かりやすい:mkfifoコマンドって使ってますか?

いつものパイプでは2プロセス間でストリーム1つ分しかやりとりできないけど、名前付きパイプなら必要な数だけ用意すればいくつでも対応できる。

$ mkfifo fifo1 fifo2
$ command1 -out1 fifo1 -out2 fifo2 &
$ command2 -in1 fifo1 -in2 fifo2
$ rm fifo1 fifo2

デッドロック対策

command1が2つの出力先に交互に出力して、command2も2つの入力を交互に読み込むような、コマンド間で入出力の順番がおおよそ一致している時はうまくいくが、場合によってはデッドロックが発生してしまう。
例えば、command1は交互に出力するけどcommand2がしばらくfifo1の方ばかり読み込むことがある状況では、

  1. command1fifo1fifo2へ交互に書き込む
  2. fifo2にだけデータが溜まっていく
  3. fifo2のバッファがいっぱいになる
  4. fifo2command1からの書き込みをブロックする
  5. 特に対策がなければcommand1fifo2のバッファが空くのを待つことになる
  6. command2fifo1を空にする
  7. command2がいくら待ってもfifo1からデータは流れてこない
  8. _人人人人人人人人_
    > デッドロック <
     ̄Y^Y^Y^Y^Y^Y^Y ̄

みたいなことがある。
パイプのバッファサイズは場合によるが、せいぜい64KiBのようだ1

対策としては、間に適当なサイズのバッファを挟むのが楽だと思われる。例えばmbufferコマンドなどがいい感じ。

$ mkfifo fifo1 fifo2
$ command1 -out1 fifo1 -out2 fifo2 &
$ command2 -in1 <(mbuffer -q -i fifo1) -in2 <(mbuffer -q -i fifo2)
$ rm fifo1 fifo2

参考

  1. How big is the pipe buffer? - パイプのバッファサイズを確認できるスクリプトの例もある

1
3
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?