連番ファイルをゼロ埋めでリネームする

Posted by 雅楽斎 on Monday, March 9, 2020

TOC

割とあるあるな話だと思います。こんなディレクトリがあるとして、

$ ls
1.jpg  10.jpg  2.jpg  3.jpg  4.jpg  5.jpg  6.jpg  7.jpg  8.jpg  9.jpg

連番が振られていると、辞書順で昇順にソートしたファイル名を表示すると、1文字目で並ぶので1,10,2,3と並びます。

GNUのlsはバージョニングスキーム順にソートする-vオプションを使用すると、上記のような場合でも1,2,3,…,10の順に表示できます。

-v natural sort of (version) numbers within text

$ ls -v
1.jpg  2.jpg  3.jpg  4.jpg  5.jpg  6.jpg  7.jpg  8.jpg  9.jpg  10.jpg

処理結果をファイルに出して別プロセスに食わせる等する場合はこれで対応可能ですが、コマンドの実行時に*で渡したい時がないでしょうか。私はものすごくあります。

ということで、ファイル名の前からゼロ埋めをした連番でリネームしていきます。参考にしたのはこちら。

大量のファイルをシェルのコマンドで一括リネームする | DevelopersIO

はじめに 大量のファイルを一括でリネームする場合、もしリネーム手順が簡素であれば、専用のスクリプトを書いたり、リネーム用のツールを使ったりせずともワンライナーで処理することができます。 前提 リネーム対象のファイルを一つ …
$ ls -v1 | awk '{ printf("%s %02d.jpg\n", $1, $1) }' | xargs -n 2 mv
mv: '10.jpg' and '10.jpg' are the same file
$ ls
01.jpg  02.jpg  03.jpg  04.jpg  05.jpg  06.jpg  07.jpg  08.jpg  09.jpg  10.jpg

ここで取っている手法は少しトリッキーです。

  • 10.jpgとかの元々2桁の番号のファイルはmvに渡す2つのファイル名が同じになるので、mv自体は実行されない(所望の動作にはなる)
  • printfでプレースホルダに置換する際に%dにファイル名を渡すことで数字部分だけを出力する”甘え”を使っているので、拡張子をその後で指定している
  • awkに渡しているファイル名がmvの対象になるので、希望しないファイル(拡張子が違うなど)が含まれる場合はlsの出力結果でフィルタリングが必要。しないとファイル名はともかく拡張子が変わってしまう

3桁にしたい場合はprintfのプレースホルダを%03dにします。

$ ls -v1 | awk '{ printf("%s %03d.jpg\n", $1, $1) }' | xargs -n 2 mv
$ ls
001.jpg  003.jpg  005.jpg  007.jpg  009.jpg
002.jpg  004.jpg  006.jpg  008.jpg  010.jpg

スポンサーリンク


comments powered by Disqus