沢山は扱いづらい
0.はじめに
大容量ストレージにデータを保存する時、特に画像データなんかは1つのディレクトリ(フォルダ)に大量のデータが割と無作為に入れることが多いと思われます。自分の場合は古いHDDからデータをサルベージした際、1つのディレクトリに14万もの画像データが入ることになりました。そうすると、普通のファイラーを使った際にデータが多すぎてファイラーの処理が重くなったりして使いづらくなります。
綺麗に分類分け出来ればもちろんいいのですが、流石に量が量なのでとりあえず適当に分割することを考えます。
1.分け方
とりあえず、ディレクトリ内の大量ファイル達を$n$等分することを考えます。
ここでは単純に考えて1つのディレクトリを2つに分けて半分に、更にその2つのディレクトリを2つずつに分けて更に半分に、…
というのを繰り返してねずみ講のように$2^k$個にディレクトリを分けて$2^k$分割する方法を取ります。(2,4,8,16,32,...)
14万個データがあるディレクトリを32分割すると大体4400個になり、まあ頑張れば扱いきれる数になります。(分割のバランスを考えるとこれくらいが妥当でしょうか。)
2.アルゴリズム
さて分け方は考えましたが、コンピュータにやらせるためにもう少しロジックを考える必要があります。アルゴリズムを考えるというヤツです。
結論から書くと以下のようになります。
1. 対象のディレクトリ内のファイル数を数えて、その半分を算出する
2. 対象のディレクトリ内のファイル一覧を出力し、その後半部分を出力する
3. ディレクトリをもう一つ作成し、対象ディレクトリ内の後半部分ファイルをそこに移動する
3.スクリプト
最終的なbash scriptは以下の通りです。
所々にあるecho
文は役割としてはprintデバッグの側面が強いので無くても問題なし。
# !/bin/bash
# ディレクトリ内の大量ファイルを2**n分割してディレクトリに分ける
if [ $# -ne 1 ]; then
echo "引数の数が違う"
exit 1
fi
# 対象のディレクトリとそこのパスを切り分ける
splite_directory=$(basename $1)
readonly splite_directory
base_directory=$(dirname $1)
readonly base_directory
echo $splite_directory
echo $base_directory
target_dir_list=($splite_directory)
count=1
while [ $count -lt 32 ]
do
new_target_dir_list=()
for t_dir in ${target_dir_list[@]};
do
echo $t_dir
# ディレクトリ内のファイル数を数えて、その半分値を算出する
num_file=$(find ${base_directory}/${t_dir}/. -type f|wc -l)
half_num=$(($num_file>>1))
echo $num_file
echo $half_num
# 対象のディレクトリ内のファイル一覧を出力し、その後半部分を作成する
ls -1 ${base_directory}/${t_dir}/. > file_list.txt
tail -q -n $half_num file_list.txt > half_list.txt
half_files=(`cat half_list.txt|xargs`)
rm file_list.txt
rm half_list.txt
# ディレクトリを2つに分割し、収納ファイル数を半分に分ける
rename_dir=${t_dir}0
new_dir=${t_dir}1
new_target_dir_list+=(${rename_dir} ${new_dir})
# 収納ファイルの後ろ半分を新しいディレクトリに移す
mkdir ${base_directory}/${new_dir}
for hf in ${half_files[@]};
do
mv ${base_directory}/${t_dir}/${hf} ${base_directory}/${new_dir}/${hf}
done
# 移し元のディレクトリを改名する
mv ${base_directory}/${t_dir} ${base_directory}/${rename_dir}
done
target_dir_list=${new_target_dir_list[@]}
count=$(($count<<1))
done