【bash】xargsを使って2つのリストをCROSS JOINする
ひとつ前のエントリの中で、2つのリストをCROSS JOINする、ということを行っています。
データの流れ
[tmp.key1]
A B I
[tmp.key2]
Ice Juice OREO
上記二つのファイルをCROSS JOINしたような感じで、下記の出力を得ます。
A,Ice A,Juice A,OREO B,Ice B,Juice B,OREO I,Ice I,Juice I,OREO
シェルスクリプトでどう書くか
- 普通のやり方 ・・・ whileを使う
- tmp.key1の各行に対し、tmp.key2の内容をくっつけて出力する、という2重ループを形成します
cat tmp.key1 | while read L1 ; do cat tmp.key2 | while read L2 ; do echo $L1,$L2 done done
- xargsを使ったやり方
- bashコマンドを利用して、xargsをネストさせる
cat tmp.key1 | xargs -I% bash -c 'cat tmp.key2 | xargs -I@ echo %,@'
ここで、bashを使用せず普通にxargsをパイプしてしまうと、思ったような出力が得られません。
cat tmp.key1 | xargs -I% cat tmp.key2 | xargs -I@ echo %,@
↓
%,Ice %,Juice %,OREO %,Ice %,Juice %,OREO %,Ice %,Juice %,OREO
※下記のような動きになってしまうイメージです
(cat tmp.key1 | xargs -I% cat tmp.key2) | xargs -I@ echo %,@
また、ここで、括弧の位置を変えても
$ cat tmp.key1 | xargs -I% (cat tmp.key2 | xargs -I@ echo %,@) bash: 予期しないトークン `(' 周辺に構文エラーがあります
とエラーになってしまいます。
(xargsに渡すのは式じゃなくてコマンドだから、なのかな)
というわけで、bashコマンドを渡してやります。
bashコマンドにコマンドを渡すには、-c オプションを使用します。
-c string If the -c option is present, then commands are read from string. If there are arguments after the string, they are assigned to the positional parameters, starting with $0.
なので、後半の処理「cat tmp.key2 | xargs -I@ echo %,@」の部分を -c の string として渡してやって、
cat tmp.key1 | xargs -I% bash -c 'cat tmp.key2 | xargs -I@ echo %,@'
とするとうまくいきます。
以上。まとまったかな。