joinコマンドで3つ以上の連番のファイルの結合
はじめに
joinで3つ以上のファイルを結合したかったけどjoinは結合できるファイル数が2だったので詰まってた.パイプも使えない.
したかったこと
1つ目のフィールドが全て同じな除去可能な値で,カンマ区切りされた1行から成るCSVファイルNo1.csv,No2.csv,No3.csv,No4.csv,No5.csvを連番でjoinコマンドを用いた結合.
シェルスクリプトを用いてこれを解決.
ファイルの内容は
No1.csv:A,B,C No2.csv:A,D,E No3.csv:A,F,G No4.csv:A,H,I No5.csv:A,J,K
解決策
とりあえずシェルスクリプトを書いて姑息的に対応したので以下に記す.
mkdir combined num=5 cp No1.csv combined/combined.csv touch combined/temp.csv for ((i = 2; i <= num; ++i)) do str="" str+="No" str+=$i str+=".csv" if [ `expr $i % 2` -eq 0 ]; then join -t , combined/combined.csv $str > combined/temp.csv else join -t , combined/temp.csv $str > combined/combined.csv fi done if [ `wc -c < combined/combined.csv` -lt `wc -c < combined/temp.csv` ]; then rm -rf combined/combined.csv mv combined/temp.csv combined/combined.csv else rm -rf combined/temp.csv fi
大まかな流れとしては
- 1つ目のファイルを保存したい名前にコピーする.
- tempファイルを作成する.
- 奇数回目の結合ならコピーされたファイルと次のファイルを結合する.
偶数回目の結合ならtempファイルと次のファイルを結合する. - ファイルサイズが大きい方を最終的な結果とする.
シェルスクリプトではバッククォートでコマンドを括るとコマンドの実行結果を返す.そのため,joinした結果を変数に格納してsedか何かで置換すれば良いと思ったけど方法が今ひとつ分からず断念. join A B > AもAが空のファイルとなったため不可能だった.perlの-iみたいなのってないのかな.
おわりに
よくよく考えたら今回のケースだと
num=5 str="" find . -type f -print0 | xargs -0 sed -i -e "s/^A,//g" for ((i = 1; i <= num; ++i )) do str+="No" str+=$i str+=".csv " done paste $str
で良かった.シェルスクリプトにおける条件分岐が分からなかったりと時間を浪費した.