くんすとの備忘録

IT系技術メモ

移転しました。

15秒後に自動的にリダイレクトします。

【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 %,@'

とするとうまくいきます。
 

以上。まとまったかな。