[Shell]指定数でのCSVファイル分割とディレクトリ作成

1 min読了の目安(約1700字TECH技術記事
  • 業務でShellで大きいCSVファイルを扱う場合がある。
  • その際に、事前に分割フォルダ分けを行うことで、扱いやすくなることがある。
  • そのため今回は、Shellで行数に応じてファイル分割やフォルダ分類を行う方法を記録する。

結果

  • 以下、実行前のディレクトリ構造。
    • sample.csvは行数100のデータ
.
├── sample.csv
├── main.sh
  • 以下、main.shの記述。
#!/bin/bash
set -ex

# パス
THIS_DIR=$(cd "$(dirname "${BASH_SOURCE:-$0}")" && pwd)
DATA_FILE="${THIS_DIR}/sample.csv"
# 1列目
ID=$(grep "^[0-9]" $DATA_FILE | awk -F, '{print $1}')
# 行数
ROW=$(echo "$ID" | wc -l)
# 分割数
SEP=25
# 作成ディレクトリ数(割り切れない場合は切り上げ)
MAKE_DIR_COUNT=$(awk -v row="$ROW" -v sep="$SEP" 'BEGIN {
	i=row/sep
	printf("%d\n",i+=i<0?0:0.999)
	}
	'
)
# フォルダ作成
seq -f "sample_%01.0f" 1 ${MAKE_DIR_COUNT} |
xargs mkdir -p
# ファイル分割
split -l ${SEP} -a 2 $DATA_FILE sample_
# ファイル移動
count=1
for i in `find . -type f -name "sample_*" | sort`
do
	mv $i "sample_${count}/${i//_*/_${count}}.csv"
	let count++
done
  • 上記のmain.shの記述内の以下の項目を任意の値に書き換える。

    • DATA_FILE="${THIS_DIR}/****.csv"
    • SEP=**
  • 書き換え後、以下で実行。

bash main.sh
  • 実行後、以下のディレクトリ構造になっていることを確認。
.
├── main.sh
├── sample.csv
├── sample_1
│   ├── sample_1.csv
├── sample_2
│   ├── sample_2.csv
├── sample_3
│   ├── sample3.csv
├── sample_4
│   ├── sample4.csv

補足

作成ディレクトリ数

  • 作成ディレクトリ数の計測の際に、awkを利用する。
  • その際に意識した点は以下。
    • 行数と分割数を変数として渡す。
      • awkの-vオプションを利用して安全かつ扱いやすくしておく。
    • 切り上げ処理
      • 100/15のような小数の場合、ディレクトリ作成が正常に行われないため。
      • printf処理で切り上げして整数にしておく。

ファイル分割と移動

  • 分割と移動処理は、それぞれ分けて行う。
  • その際に意識した点は以下。
    • 拡張子付与はmvで行う。
      • splitでの拡張子付与(--additional-suffix)は、Mac等ではデフォルトではないため。

参考