【Linux】CSVファイルを指定した行数で均等に分割する方法


linux-split-csv

これまで、CSVファイルの文字コードを変更して、データベースに一括登録する方法をご紹介してきましたが、ここまで来てメモリ不足という物理的な問題にぶつかってしまいました。
CSVファイルのサイズが巨大過ぎて、処理できなかったのです。
そこで今回は、Linuxsplitコマンドを使って、CSVファイルを行数が均等になるように分割し、指定したファイル数で出力する方法をご紹介します。

【参照】これまでの流れ

日本語版のExcelでCSVを作成するとShift-JIS(SJIS)で保存されるが、それを別のLinuxサーバー側のプログラムで読み込もうとすると、文字化けしてしまうことがよくある。それは日本語版Windowsの標準文字コードがShift-JISであるのに対し、プログラム側は世界で最も...
LinuxでWindowsのCSVファイルをShift-JISからUTF-8に変換する方法 - Minory
LaravelでExcelを操作するための「Laravel Excel」というパッケージがありあます。今回はそれを利用してCSVファイルをデータベースへ簡単にインポートする方法をご紹介します。CSVを使ったデータの一括登録にとても便利です!Laravel ExcelでCSVをインポートLaravel ...
Laravel ExcelパッケージでCSVデータをDBへ一括登録する方法 - Minory

CSVを同じ行数で分割

それでは、splitコマンドの基本から、使用するオプション、特定のファイル数分割するための行数の計算方法など、順を追って紹介していきます。

splitコマンドの使い方

基本的にはこれだけで分割できます。
split [オプション] [元ファイル名] [出力ファイル名]
オプションには、-bのバイト数や-lの行単位を指定して分割する方法があります。

基本使用例

# 1000バイト(1kb)で分割する
split -b 1000 data.csv data_

# 1000行で分割する
split -l 1000 data.csv data_

しかし、このように分割するとファイル名が、

data_aa
data_ab
data_ac
・・・

という具合に、連番ではなくアルファベットで出力されてしまいます。
これでは、スクリプトでループしたい場合などにとても不便です。

ファイル名を連番にする

それを解決してくれるのが、-dオプションです。
-dオプションを付けると、デフォルトで2桁の数字に変更してくれます。
桁数を変えたい場合は、-aオプションを使います。

# 1000行で分割して、ファイル名に3桁の連番を付ける
split -l 1000 -d -a 3 data.csv data_

実行するとこのようになります。

data_000
data_001
data_002
・・・

ファイル名に拡張子をつける

さぁ!ここで最後の問題!
CSVファイルなのに分割後は拡張子(.csv)が付いてないですよね?
それを解決すべく、更に–additional-suffixオプションを追加します。
その名の通り、これで拡張子を付けてくれるんですね。

splitまとめ

以上のことを踏まえてまとめると、以下のようなコマンドが完成します。

split -l 1000 -d -a 3 data.csv data_ --additional-suffix=.csv

参考:【split】Linuxでファイル分割するコマンド | UX MILK


行数を均等に分割する方法

wcコマンドで全体の行数を出し、awkコマンド割り算した結果を変数に入れます。

rows=`wc -l data.csv | awk '{printf("%d",(($1 / 10) + 1))}'`

ちょっとだけポイントを解説。
ファイルを10分割(/ 10)しています。
“%d”で整数だけを取得。
+ 1は割り切れなかった場合に備えて1を足しています。
1行多くなったりするので、キッチリ均等になりませんが別にいいでしょ?

まとめのまとめ

そして、計算結果を先程の[1000]の箇所に入れてあげれば完成です。

rows=`wc -l data.csv | awk '{printf("%d",(($1 / 10) + 1))}'`
split -l $rows -d -a 3 data.csv data_ --additional-suffix=.csv
番外編

この書き方だけが全てではないのがコンピュータですね。
他の方法も紹介されてましたので、紹介して終わりにします。
以下、ファイルを真っ二つに分割する例です。

split -l $(expr $(wc -l foo.txt | cut -d " " -f 1) / 2 + 1) foo.txt bar.

参考:ファイルを真っ二つに分割する – drag n drop

以上、お疲れ様でした。


コメント

このブログの人気の投稿

Linuxでファイルの改行コードLF⇔CRLFを変換する方法

RHEL 7でスタティック(静的)ルートを追加する4つの方法

SQLPlusでのOracleリモート接続とSQLファイルを実行する方法