【Linux】【シェル】1つのCSVファイルを複数のファイルに分割するサンプル
-
カテゴリ:
- サーバ
-
タグ:
- #Linux
単純に1つファイルを複数のファイル分割するだけなら「split」コマンドを使えば簡単にできます。
$ split -l 100 [分割対象のファイルパス] [ファイルの出力先のパス]
しかしCSVファイルの場合、1行目にヘッタ項目が付いていることが多く、分割したそれぞれのファイルに対してヘッタを付与することを考えると、「split」コマンドだけでは難しいです。
そこでヘッタ付きCSVファイルを分割するシェルを作成してみました。
サンプルとしてCSVデータ「sample01.csv」とシェル「split_file.sh」を用意しました。
[user@localhost sh]$pwd
/home/user/test/sh
[user@localhost sh]$ ll
合計 8
-rw-r--r-- 1 user user 4695 12月 11 23:05 sample01.csv
-rw-r--r-- 1 user user 1951 12月 11 23:19 split_file.sh
[user@localhost sh]$
CSVデータ「sample01.csv」の内容は以下の通りです。
NO,CD,TEST
1,10,aaaa
2,20,aaaa
3,30,aaaa
4,40,aaaa
5,50,aaaa
6,60,aaaa
7,70,aaaa
8,80,aaaa
9,90,aaaa
10,100,aaaa
11,110,aaaa
・・・・
345,3450,aaaa
346,3460,aaaa
347,3470,aaaa
348,3480,aaaa
349,3490,aaaa
350,3500,aaaa
ヘッタも併せて、計351レコードあるCSVファイルです。
実際のシェルスクリプトを見てみましょう。
split_file.sh
#!/bin/bash
echo "=============== ディレクトリ作成処理 START ==============="
# 分割する対象ファイルのあるディレクトリを指定
BASE_PATH='/home/user/test/sh/'
# 分割対象のファイル名
FILE_NAME='sample01.csv'
# 何行ごと分解するか指定
LINE=100
# 作業用ファイル
WORK_FILE_NAME='w_'$FILE_NAME
# ファイル名から拡張子を取り除く
SPLIT_FILE="${FILE_NAME%.*}"'_'
SPLIT_FILE_PATH=$BASE_PATH$SPLIT_FILE
# 拡張子を抽出
FEXT="${FILE_NAME##*.}"
BASE_FILE_PATH=$BASE_PATH$FILE_NAME
WORK_FILE_PATH=$BASE_PATH$WORK_FILE_NAME
echo "---------- 作業用ファイル作成 START ----------"
`cp $BASE_FILE_PATH $WORK_FILE_PATH`
echo "---------- 作業用ファイル作成 END ----------"
echo "---------- ヘッタを抽出 START ----------"
# CSVのヘッターを取得
HEADER=`head -n 1 $WORK_FILE_PATH`
# ファイルの先頭行(ヘッタ)を削除する
`sed -i -e '1d' $WORK_FILE_PATH`
echo "---------- ヘッタを抽出 END ----------"
echo "---------- ファイル分割(100行ずつ) START ----------"
`split -l $LINE $WORK_FILE_PATH $SPLIT_FILE_PATH`
echo "---------- ファイル分割 END ----------"
echo "---------- CSVのヘッタを挿入 START ----------"
cd $BASE_PATH
for file in `\find -name $SPLIT_FILE"*"`; do
`mv $file $file.$FEXT`
# ヘッタを挿入
`sed -i -e "1s/^/${HEADER}\n/" $file.$FEXT`
done
echo "---------- CSVのヘッタを挿入 END ----------"
echo "---------- 作業用ファイル削除 START ----------"
`rm $WORK_FILE_PATH`
echo "---------- 作業用ファイル削除 END ----------"
echo "=============== ディレクトリ作成処理 END ==============="
# [補足]拡張子の付与(CSV)を一行でやる場合
# find -name $SPLIT_FILE"*" | xargs -i mv {} {}/
# [補足]末尾にヘッタを追加する場合
# echo $HEADER >> $file.csv
ポイントとなるのが「split」コマンドと「sed」コマンドです。
「split」コマンドは記事の最初にも説明しましたがファイルを分割するためのコマンドで、「-l 100」とオプションを指定することで100行ごと分割することができます。
「sed」コマンドは文字列を置換するためのコマンドです。上記サンプルソースの30行目では、「sed」のdオプションを利用して先頭行の文字列を削除しています。
さらに、45行目では「-i」オプションと「-e」オプションを使って先頭の空白を対象の文字列に置換することで、先頭にヘッタを挿入しています。
実行前はシェルとCSVファイルが1ずつあるだけでしたが、split_file.shを実行すると分割されたCSVが作成されています。
[user@localhost sh]$ sh ./split_file.sh
[user@localhost sh]$ ll
合計 12
-rw-r--r-- 1 user user 4695 12月 11 23:05 sample01.csv
-rw-r--r-- 1 user user 1195 12月 11 23:17 sample01_aa.csv
-rw-r--r-- 1 user user 1411 12月 11 23:17 sample01_ab.csv
-rw-r--r-- 1 user user 1411 12月 11 23:17 sample01_ac.csv
-rw-r--r-- 1 user user 711 12月 11 23:17 sample01_ad.csv
-rw-r--r-- 1 user user 1951 12月 11 23:19 split_file.sh
[user@localhost sh]$
分割されたそれぞれのファイルの内容は以下の通りです。
sample01_aa.csv
NO,CD,TEST
1,10,aaaa
2,20,aaaa
3,30,aaaa
4,40,aaaa
5,50,aaaa
・・・・
95,950,aaaa
96,960,aaaa
97,970,aaaa
98,980,aaaa
99,990,aaaa
100,1000,aaaa
sample01_ab.csv
NO,CD,TEST
101,1010,aaaa
102,1020,aaaa
103,1030,aaaa
104,1040,aaaa
105,1050,aaaa
・・・・
195,1950,aaaa
196,1960,aaaa
197,1970,aaaa
198,1980,aaaa
199,1990,aaaa
200,2000,aaaa
sample01_ac.csv
NO,CD,TEST
201,2010,aaaa
202,2020,aaaa
203,2030,aaaa
204,2040,aaaa
205,2050,aaaa
・・・・
295,2950,aaaa
296,2960,aaaa
297,2970,aaaa
298,2980,aaaa
299,2990,aaaa
300,3000,aaaa
sample01_ad.csv
NO,CD,TEST
301,3010,aaaa
302,3020,aaaa
303,3030,aaaa
304,3040,aaaa
305,3050,aaaa
・・・・
345,3450,aaaa
346,3460,aaaa
347,3470,aaaa
348,3480,aaaa
349,3490,aaaa
350,3500,aaaa
作成したサンプルシェルは対象ファイルをソース上にべた書きしているので汎用性がありませんが、ファイルパスを実行にパラメータとして渡してやるとか、シェルの置かれている直下を対象とするかいろいろ応用が利くと思います。
自分のシェルが全ての環境に対応できる自信は無いので、一部を流用するなど参考にして頂ければ幸いです。
以上! (´◡`)ノ