ファイル名の数字の桁数を揃えたい

LINEで送る
Pocket

連番のファイル群を参照する時に、ソートが意図した通りにならなかった事は無いでしょうか? 1 の後は 2 3 と連番になって欲しいけれど、1 の後が 10 11 .. 、2 の後が 20 21 … となってしまう。ls コマンドは、あくまで文字コードの順番でソートされるので数字の番号を意識してくれません。しかし番号の桁数を1 -> 001 や、10 -> 010 と揃えれば、文字コードの順番に番号が連番にソートされるようになります。しかしこの手のファイルはディレクトリに沢山あって手動で1つずつ変更するのは手間がかかります。今回はいくつかのパターンに対応したファイル名に含まれている番号の桁数をそろえるスクリプトを紹介したいと思います。

$ ls
1.txt  10.txt  11.txt  2.txt  3.txt  4.txt  5.txt  6.txt  7.txt  8.txt  9.txt
$ ls
file_1.txt  file_10.txt  file_11.txt  file_2.txt  file_3.txt  file_4.txt  file_5.txt  file_6.txt  file_7.txt  file_8.txt  file_9.txt
$ ls -1
1.txt
10.txt
11.txt
2.txt
3.txt
   :

実行例

# ファイルリストを表示
$ ls
1.txt  10.txt  2.txt  P_20220401_1.jpg  P_20220401_10.jpg  P_20220401_2.jpg  file_1.txt  file_10.txt  file_2.txt  filename_sort.sh
# スクリプトを実行
$ ./filename_sort.sh
1.txt -> 001.txt
10.txt -> 010.txt
2.txt -> 002.txt
P_20220401_1.jpg -> P_20220401_001.jpg
P_20220401_10.jpg -> P_20220401_010.jpg
P_20220401_2.jpg -> P_20220401_002.jpg
file_1.txt -> file_001.txt
file_10.txt -> file_010.txt
file_2.txt -> file_002.txt
# 変更内容がよければ yes と入力
ファイル名を変更しますか?(Yes/No) yes
mv 1.txt 001.txt
mv 10.txt 010.txt
mv 2.txt 002.txt
mv P_20220401_1.jpg P_20220401_001.jpg
mv P_20220401_10.jpg P_20220401_010.jpg
mv P_20220401_2.jpg P_20220401_002.jpg
mv file_1.txt file_001.txt
mv file_10.txt file_010.txt
mv file_2.txt file_002.txt
# ファイルリストが意図した通りの順番になっているのか確認
$ ls
001.txt  002.txt  010.txt  P_20220401_001.jpg  P_20220401_002.jpg  P_20220401_010.jpg  file_001.txt  file_002.txt  file_010.txt  filename_sort.sh

filename_sort.sh

#!/bin/bash
# デリミタを改行に設定
IFS=$'\n'
# ループ終了フラグ
END_FLAG=1
# 変更フラグ
MV_FLAG=0
while [ ${END_FLAG} = "1" ];
do
	# 数字を含むファイルを検索 file_XXX.txt XXX.txt P_20220401_XX.jpg などを対象
	for line in `ls |grep -P '[^0-9]*[^0-9]*[0-9]+\.[a-zA-Z]+$'`
	do
		# デリミタをタブにしてファイル名を抽出 file_XXX.txt -> file XXX .txt 
		TMP_FILENAME=`echo "${line}"|sed -r 's/([^0-9]*[^0-9]*)([0-9]+)(\.[a-zA-Z]+$)/\1\t\2\t\3/'`
		# ファイル番号を取得
		FILENO=`echo "${TMP_FILENAME}" | awk -F "\t" '{print $2}'`
		# 桁数を 3 桁に揃える
		FILENO=`printf %03d ${FILENO}`
		# 数字以外のファイル名を取得
		FILENAME=`echo "${TMP_FILENAME}" | awk -F "\t" '{print $1}'`
		# ファイルの拡張子を取得
		EXT=`echo "${TMP_FILENAME}" | awk -F "\t" '{print $3}'`
		if [ ${MV_FLAG} = "1" ]; then
			# ファイル名を変更
			echo "mv ${line} ${FILENAME}${FILENO}${EXT}"
			mv "${line}" "${FILENAME}${FILENO}${EXT}"
		else
			# 変更候補リストを表示
			echo "$line -> $FILENAME$FILENO$EXT"
		fi
	done

	# ループ終了
	if [ ${MV_FLAG} = 1 ]; then
		break
	fi

	# 変更確認を表示
	echo -n "ファイル名を変更しますか?(Yes/No) "
	read MV_OK
	case $MV_OK in
		# yes と入力されたら MV_FLAG を立て、ループに戻る。
		[Yy][Ee][Ss] | [Yy][Ee] | [Yy] )
			MV_FLAG=1
			;;
		* )
		# END_FLAG を下げてループを終了
			echo "キャンセルされました。"
			END_FLAG=0
			;;
	esac

done
LINEで送る
Pocket

  • このエントリーをはてなブックマークに追加

コメントを残す

*

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください