今回は、Linuxのsplitコマンドを使って、CSVファイルを行数が均等になるように分割し、指定したファイル数で出力する方法をご紹介します。
これまで、CSVファイルの文字コードを変更して、データベースに一括登録する方法をご紹介してきましたが、ここまで来てメモリ不足という物理的な問題にぶつかってしまいました。
CSVファイルのサイズが巨大過ぎて、処理できなかったのです。
CSVを同じ行数で分割
それでは、splitコマンドの基本から、使用するオプション、特定のファイル数で分割するための行数の計算方法など、順を追って紹介していきます。
splitコマンドの使い方
基本的にはこれだけで分割できます。
1 |
split [オプション] [元ファイル名] [出力ファイル名] |
オプションには、[-b]のバイト数や[-l]の行単位を指定して分割する方法があります。
基本使用例
1 2 3 |
# 1000バイト(1kb)で分割する split -b 1000 data.csv data_# 1000行で分割する split -l 1000 data.csv data_ |
しかし、このように分割するとファイル名が、
1 2 3 4 |
data_aa data_ab data_ac ・・・ |
という具合に、連番ではなくアルファベットで出力されてしまいます。
これでは、スクリプトでループしたい場合などにとても不便です。
ファイル名を連番にする
それを解決してくれるのが、[-d]オプションです。
[-d]オプションを付けると、デフォルトで2桁の数字に変更してくれます。
桁数を変えたい場合は、[-a]オプションを使います。
1 2 |
# 1000行で分割して、ファイル名に3桁の連番を付ける split -l 1000 -d -a 3 data.csv data_ |
実行するとこのようになります。
1 2 3 4 |
data_000 data_001 data_002 ・・・ |
ファイル名に拡張子をつける
さぁ!ここで最後の問題!
CSVファイルなのに分割後は拡張子(.csv)が付いてないですよね?
それを解決すべく、更に[–additional-suffix]オプションを追加します。
その名の通り、これで拡張子を付けてくれるんですね。
splitまとめ
以上のことを踏まえてまとめると、以下のようなコマンドが完成します。
1 |
split -l 1000 -d -a 3 data.csv data_ --additional-suffix=.csv |
行数を均等に分割する方法
[wc]コマンドで全体の行数を出し、[awk]コマンドで割り算した結果を変数に入れます。
1 |
rows=`wc -l data.csv | awk '{printf("%d",(($1 / 10) + 1))}'` |
ちょっとだけポイントを解説。
ファイルを10分割(/ 10)しています。
“%d”で整数だけを取得。
+ 1は割り切れなかった場合に備えて1を足しています。
1行多くなったりするので、キッチリ均等になりませんが別にいいでしょ?
CSVを分割する方法まとめ
そして、計算結果を先程の[1000]の箇所に入れてあげれば完成です。
1 2 |
rows=`wc -l data.csv | awk '{printf("%d",(($1 / 10) + 1))}'` split -l $rows -d -a 3 data.csv data_ --additional-suffix=.csv |
番外編(おまけ)
この書き方だけが全てではないのがコンピュータですね。
他の方法も紹介されてましたので、紹介して終わりにします。
以下、ファイルを真っ二つに分割する例です。
1 |
split -l $(expr $(wc -l foo.txt | cut -d " " -f 1) / 2 + 1) foo.txt bar. |
以上、お疲れ様でした。
コメント