理系学生日記

おまえはいつまで学生気分なのか

Bash のプロセス置換が便利な件

Bash にはプロセス置換という便利な機能があります。しかしこの機能、あまり知名度が高くない。 ぼくは毎日の労働に疲れ果てているし、日本学生支援機構という組織から毎月金を請求され、しまいには信用情報機関に登録される寸前までいくような生活を送っているというような状態なので、みなさんにこのプロセス置換という機能をご説明して気を紛らわすことに決めた。

プロセス出力をファイルとして扱うと便利なケース

一般に、unix でファイルの差分をチェックするには diff を使います。 例えば、それぞれ 1〜3 と 1〜4 が順番に入力された 2 つのファイルがあるとすると、次のような感じで比較しますね。 瞬時に 4 だけが仲間外れであることが分かり、同質であることを良しとし異端を排除する日本においては、杭として打たれ、イジメの対象となります。とてもこわいですね。はーこわい。

$ diff -u seq3.dat seq4.dat
--- seq3.dat 2012-09-08 13:01:10.000000000 +0900
+++ seq4.dat 2012-09-08 13:01:14.000000000 +0900
@@ -1,3 +1,4 @@
 1
 2
 3
+4

一方で、数字順でなく、ランダムで並べられた数字の入った 2 つのファイルでどの数字が仲間外れかを調べるときを考えましょう。 diff は行ベースでファイル先頭から比較するので、ソートしないと目的を果たせません。 ソートしなくっちゃーってことになって、ソート済状態を保持する一時ファイルが生成されて、はー、ゴミファイルが残るのダルいですーっていうことになる。

$ sort -n shuffle3.dat > shuffle3.dat.sorted
$ sort -n shuffle4.dat > shuffle4.dat.sorted
$ diff -u shuffle[34].dat.sorted
--- shuffle3.dat.sorted  2012-09-08 13:10:03.000000000 +0900
+++ shuffle4.dat.sorted  2012-09-08 13:10:08.000000000 +0900
@@ -1,3 +1,4 @@
 1
 2
 3
+4

でもこれ、プロセス置換を使うとゴミファイルが残らなかったりして便利。

$ diff -u <(sort -n shuffle3.dat) <(sort -n shuffle4.dat)
--- /dev/fd/11   2012-09-08 13:13:54.000000000 +0900
+++ /dev/fd/12   2012-09-08 13:13:54.000000000 +0900
@@ -1,3 +1,4 @@
 1
 2
 3
+4

bash 自身で一時ファイルを作成したり、名前付きパイプで実現されていたりするみたいですが、詳細はシステムによって異なるっぽいので、man bash で Process Substitution を読むと良いと思う。

パイプの分岐

シェルにおいてパイプラインというのは非常に便利な機能で、これ使わないことはまずないと思います。 で、パイプラインの先を分岐させたいときがある。標準出力を 2 つのファイルに書き出したいときには、例えばパイプの後段に tee を繋ぎますね。

$ echo "hello world" | tee hello.dat
hello world
$ cat hello.dat
hello world

しかし、ファイル出力ではなく、パイプの後段に 2 つのコマンドを並列して繋ぎたいときがある。納品物の MD5 ファイルを作成するとともに、gzip で固めたい、といったケースですね。 これ、直感的には 2 行で書きますがダルい。実際にはダルくないけどダルいと書いておかないと話が続かないのでダルいことにします。

$ md5sum product > product.md5
$ gzip product

これ、実はプロセス置換を使えば 1 行で書ける。

$ cat product | tee >(md5sum > product.md5) | gzip > product.gz

ぜったいにプロセス置換使った後者のほうがダルいと思う。素直に 2 つのコマンドに分けたほうがいいとおもう。