アメリエフの技術ブログ

Amelieff Staff Blog

joinコマンドで少し手間取った話

過ごしやすい季節から段々暑い日が多くなってきましたね.
暑いのが苦手な夏生まれのh--ishiです.


最近,複数テキストファイル(表データ)をLinuxのjoinコマンドで連結することがあり,
少し手間取ったので備忘録として書き遺しておきます.


joinとは...
二つのテキストファイルの共通のキーをもつ行を連結して,一つの行にまとめてくれるLinuxのコマンドです


具体例をだして,やっていきたいと思います.
下のような,店A,Bでの肉の商品名とその値段に関する二つの表があったとします.
これらの表を一つの表にまとめたい!ということですね.
(実際には,2つのサンプルの実験結果の表を1つの表にまとめるということが想定されそうです.)

お店Aでのお肉の価格(storeA.txt)

商品名  店Aでの値段(JPY)
ゴブリンの肉    100
ベヒーモスの肉  500
ガーゴイルの肉  1000



お店Bでのお肉の値段(storeB.txt)

商品名  店Bでの値段(JPY)
ゴブリンの肉    100
ベヒーモスの肉  50
ガーゴイルの肉  2000
キマイラの肉    10000


上の2ファイルをjoinコマンドで連結してみましょう
$ join -a 1 -a 2 -j 1 -o 1.1,1.2,2.2 -e NA --header storeA.txt storeB.txt > merge.txt

用いたオプションは
-a: 参照したファイル間で共通していない行も出力(-a 1 の場合,storeAに特有の行も出力する)
-j: 参照したファイル間において比較する列番号(今回は商品名でまとめるので,"1"です)
-o: 各参照ファイルの出力する列番号(1.1,1.2,2.2だと1「個目のファイルの1列目と2列目,2個目のファイルの2列目を出力する」という意味.)
-e: 共通していない行について,カラムにいれる文字を指定する(今回の場合NAを入れた)
--header: 一行目をヘッダーと認識する


- ハマった点1:joinはsortする必要がある! 僕はこれを知らずにjoinを行ないまして,ソートしてくださいと怒られました.
(僕がつくった上の表では元々ソートされた状態で作ってしまったので怒られませんでしたが,実際に扱っているデータでは怒られました.)
ファイルの行のソートは,sortコマンドで行います.


- ハマった点2: sortはheaderを認識してくれない!!! 怒られてしまいましたので,仕方ない...sortを行います.

$ sort storeA.txt 
ガーゴイルの肉   1000
ゴブリンの肉  100
ベヒーモスの肉   500
商品名   店Aでの値段(JPY)

ヘッダーもソートされてしまった...もはやヘッダーではない!
オプションを探しても,ヘッダーを認識するオプションはなさそう...
人力で,ヘッダー行を削ってsortしてあとからヘッダーをつけるなども考えられますが,面倒ですよね?
なので,こんな作戦がたてられます.


1. head コマンドでヘッダーを抽出する
2. tail コマンドでヘッダー以外を抽出したものをソートする
3. 1. と2. とを子bashで実行して連結する

$ (head -n 1 storeA.txt && tail -n +2 storeA.txt | sort ) > storeA_sorted.txt
ヘッダーがあるソート済みファイルが完成しました.

商品名  店Aでの値段(JPY)
ガーゴイルの肉  1000
ゴブリンの肉    100
ベヒーモスの肉  500




$ join -a 1 -a 2 -j 1 -o 0 1.1,1.2,2.2 -e NA --header storeA_sorted.txt storeB_sorted.txt > merge.txt

商品名 店Aでの値段(JPY) 店Bでの値段(JPY)
ガーゴイルの肉 1000 2000
NA NA 10000
ゴブリンの肉 100 100
ベヒーモスの肉 500 50



以上,僕が二つのファイルをjoinコマンドでつまづいた赤裸々告白でした(照)