読者です 読者をやめる 読者になる 読者になる

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. 1つ目のファイルを保存したい名前にコピーする.
  2. tempファイルを作成する.
  3. 奇数回目の結合ならコピーされたファイルと次のファイルを結合する.
    偶数回目の結合ならtempファイルと次のファイルを結合する.
  4. ファイルサイズが大きい方を最終的な結果とする.

シェルスクリプトではバッククォートでコマンドを括るとコマンドの実行結果を返す.そのため,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

で良かった.シェルスクリプトにおける条件分岐が分からなかったりと時間を浪費した.