【コラム】
zshにはプロセス置換(Process Substitution)と呼ばれる機能がある。これはファイルを指定すべき場所や、パイプとして処理すべきところを「コマンドやコマンドの組み合わせそのもの」を記述して処理するいう機能だ。コマンドをファイルのように扱えるものといってもよい。
| 記述方法 | 内容 |
|---|---|
| <(コマンドリスト) | コマンドの結果をファイルとして扱う |
| >(コマンドリスト) | 出力先をコマンドに渡す |
コマンドで指定するファイルをファイルではなくコマンドとして直接指定することで、一時ファイルを作成する必要がなくなる。どれだけ使うシーンがあるかと問われると頭を捻ってしまうが、ログ解析や差分チェックなどを使っている人からは「けっこう便利に使っている」という話も聞く。
さあ、今回はこのマニアックな機能を堪能していこう。ちなみに今回の内容はその多くをzshマニュアルの「Process Substitution」の項を参考にしている。コマンド例もこれを参考にしたものだ。より詳しく知りたい読者の方は、そちらも合わせてご覧いただきたい。
CSVファイルを編集する例を考えてみよう。表2.1のようなテーブルデータを用意したとしよう。テキスト状態ではプロンプト2.1のようになっている。
| 氏名 | 年齢 | 性別 | 備考 |
|---|---|---|---|
| Zsher01 | 32 | Male | Both bash |
| Zsher02 | 32 | Male | |
| Zsher03 | 35 | Female | |
| Zsher04 | 32 | Male | From tcsh |
| Zsher05 | 35 | Male | From bash |
% cat sheet01.csv
"氏名","年齢","性別","備考"
"Zsher01",32,"Male","Both bash"
"Zsher02",32,"Male",
"Zsher03",35,"Female",
"Zsher04",32,"Male","From tcsh"
"Zsher05",35,"Male","From bash"
%
例えばこのファイルから、氏名と年齢の2列だけを取り出したいとする。これにはさまざまな方法があるが、一例としてcut(1)コマンドを使えばプロンプト2.2のようになる。
% cut -f 1,2 -d, sheet01.csv
"氏名","年齢"
"Zsher01",32
"Zsher02",32
"Zsher03",35
"Zsher04",32
"Zsher05",35
%
わざわざプロセス置換で同じことをする必要はないわけだが、説明を分かりやすくするために、同じことをプロセス置換でやってみる。cut(1)コマンドはプロンプト3.1やプロンプト3.2のようにすれば1列ずつ取り出せる。これらを組み合わせてプロンプト2.2のようにしてみよう。
% cut -f 1 -d, sheet01.csv
"氏名"
"Zsher01"
"Zsher02"
"Zsher03"
"Zsher04"
"Zsher05"
%
% cut -f 2 -d, sheet01.csv
"年齢"
32
32
35
32
35
%
paste(1)コマンドで出力結果をマージすればプロンプト3.3のようになる。これを見れば、コマンドの出力がそのままファイルを指定した場合のように扱われていることが分かるだろう。
% paste <(cut -f 1 -d, sheet01.csv) <(cut -f 2 -d, sheet01.csv)
"氏名" "年齢"
"Zsher01" 32
"Zsher02" 32
"Zsher03" 35
"Zsher04" 32
"Zsher05" 35
%
プロセス置換は使われるシーンやシステムに用意されている機能などによって、場合によって/dev/fd/?のファイルへの置換、FIFO(名前付きパイプ)、パイプなどの機構に置き換えて実行される。つまりプロンプト3.3の場合、paste(1)コマンドとしてはファイルが指定された場合と処理は何ら変わっていないということだ。試しにdiff(1)コマンドなどで実行してみれば、実際にはどういったファイルが使われているかが分かる。
% diff -u <(cut -f 1 -d, sheet01.csv) <(cut -f 2 -d, sheet01.csv)
--- /tmp/zshiA99oo Thu May 10 19:57:03 2007
+++ /tmp/zshYfMoLl Thu May 10 19:57:03 2007
@@ -1,6 +1,6 @@
-"氏名"
-"Zsher01"
-"Zsher02"
-"Zsher03"
-"Zsher04"
-"Zsher05"
+"年齢"
+32
+32
+35
+32
+35
%
例えばプロセス置換に"; sleep 10"あたりを仕込んで「diff -u <(cut -f 1 -d, sheet01.csv; sleep 10) <(cut -f 2 -d, sheet01.csv)」のように実行し、プロンプト3.5のようにfile(1)コマンドを使えば、プロセス置換がFIFO(名前付きパイプ)に置き換えられていることが分かる。
% file /tmp/zsh*
/tmp/zshiA99oo: fifo (named pipe)
/tmp/zshYfMoLl: fifo (named pipe)
%
要するに一時ファイルはzshが適当に用意してくれるわけだ。
コマンドの出力をファイルではなく、逆に出力をコマンドに流し込む指定が「>(コマンドリスト)」だ。コマンドの出力を複数のコマンドリストに流し込むことができる。少々分かりにくいかもしれないが、プロンプト3.3のコマンドの出力を2つの処理に渡して処理する例をプロンプト4.1に示す。
% atoZ() { tr "[a-z]" "[A-Z]" }
% Atoz() { tr "[A-Z]" "[a-z]" }
% paste <(cut -f 1 -d, sheet01.csv) <(cut -f 2 -d, sheet01.csv) \
> >(grep 32 | atoZ) > >(grep 35 | Atoz)
"ZSHER01" 32
"ZSHER02" 32
"ZSHER04" 32
"zsher03" 35
"zsher05" 35
%
「>(コマンドリスト)」についてだが、コマンドにそのまま流し込みたいので「> >(コマンドリスト)」のようにリダイレクトも併用している。これでパイプで流した場合と同じような効果がある。このあたりは理解しにくいかもしれないが、「>(コマンドリスト)」に対してリダイレクト「>(コマンドリスト)」しているので「> >(コマンドリスト)」だ。パイプで同じことをするなら「| tee >(コマンドリスト) > /dev/null」のようにすればよい。
コマンドによっては引数にファイルしか受け取らず、パイプ、要するに標準入力を受け付けないものがある。代わりに出力に標準出力(やパイプ)を指定できずファイルしか指定できないものがある。プロセス置換を使うと、そういったファイルに対しても一時ファイルを作成することなく処理ができるわけだ。パイプが使えないコマンドに対する代替処置ととらえてもよいだろう。
プロセス置換をゴリゴリ活用するときがあるかと言われると、はっきり言って筆者にはほとんどない。しかしながら使っている人の話によると、使えば便利な機能だそうだ。また、都合によりサーバで一時ファイルを作成したくない(または作成できない)場合や、シェルスクリプトにおいて一時ファイルを考えたくない場合などには、便利な機能である。
【コラム】イマドキのIDE事情 第6回 EclipseでPHP開発! PHP Development Tools
【コラム】ダイナミックObjective-C 第75回 デザインパターンをObjective-Cで - Decorator (2)
| 花粉の運び屋“マルハナバチ”の国勢調査 [18:11 5/24] |
| 「Arid5a」は自己免疫疾患を引き起こすカギ分子の可能性大 - 阪大 [17:39 5/24] |
| 岡山大、中枢神経の「ランビエ絞輪」形成機構の解明に1歩前進 [17:35 5/24] |
| 細胞間接着を担うタンパク質「クローディン」に関する発見 - 阪大など [17:32 5/24] |
| パナソニック、LEDに匹敵する照明用高効率白色有機EL素子を開発 [17:29 5/24] |
|
[探偵はBARにいる]第3弾の製作決定 大泉洋ガッツポーズで歓喜 [12:36 5/26] エンタメ |
|
「ガンダム」原画集を安彦が語るインタビュー、ダムエーに [12:26 5/26] ホビー |
|
[47都道府県芸人グルメ便]「宇都宮餃子」 栃木・上原チョー [12:15 5/26] ホビー |
|
[長友佑都選手]ディズニーXDでアニメ化 6月14日放送開始 [12:00 5/26] ホビー |
|
【インタビュー】「向井理は日本一スーツの似合う男、ハリウッド黄金時代の役者に近い」- 青山真治監督が語るドラマ『最上のプロポーズ』 [12:00 5/26] エンタメ |