[bash][ワンライナー]抜け番のある連番ファイルをリネームする


スクリーンショット画像などを整理する際、連番のファイル名を手動でリネームするのは骨が折れますよね?ダメ写真を削除したりして、抜け番が生じることもあるかと思います。しかし、bashのforループを使えばすんなりリネームすることができるので、是非試してみてください。まずはファイルの一覧を見てみましょう。

ご覧のように、ファイル名はすべて接頭語が「OS_INSTALL_」で、連番は4桁の数字になっています。

数が多くてわかりにくいかと思いますので、抜け番があるあたりを見てみましょう。以下のように、23番目のファイルが抜けていることがわかります。

全体でどれだけ抜けがあるのかは ls コマンドをパイプで wc に渡してみるとわかります。

ご覧のように、連番のファイルが113まであるのに対してファイルの数は107です。

■ 桁数を無視してとりあえずはリネームする例 (あまり行儀がよろしくない)

ファイル名に抜け番があるということは、先ほどの例のように、ファイル名に含まれる番号の最大値よりも実際のファイル数のほうが少ないわけです。これを自動でリネームするということは、抜け番の次にある番号がその抜け番号を埋める、つまりファイル名がデクリメントされていくというわけです。まずはリネームの一部を見てみましょう。なお、このコマンドを実行した時点ではまだリネームされません。

桁数を無視してよいなら、awkの次のパイプに sh を渡してあげて実行しておしまいです。しかしこれでは折角元のファイルがゼロパディングでソートできているのに、台無しになってしまいます。

■ 桁数を揃えてリネームする例 (少しマシな実行例)

桁数を揃えたままリネームするなら、以下のようにするとよいでしょう。なお、今回の例でもコマンド実行時にはまだリネームされません。動作を確認するため、 mv コマンドの前に echo とタイプすることで「やっちまった!」を防いでいます。確認後OKなら echo を削るか、forループが終わったあと、つまり done の後にパイプで sh コマンドに渡してあげましょう。私はいつも done のあとに sh に渡しています。その方がOPミスで間違う可能性が低いからです。

上記の例のように、抜け番が埋められているのがおわかりいただけるかと思います。ただし、ちょっと工夫をしています。

最初に変数numを指定する前に、 declare コマンドで、「変数 num は数値型ですぜ」と宣言しています。これがあるおかげで、forループの最後に num 変数 に 1 を足して、ループが続く限りカウントアップされます。

続いて、ファイル名ですが、最初のアンダーバーをハイフンに置換しています。mvの前にif文でファイルの有無を見るほうが本当はよいのですが、まずはリネームできること優先でやっています。リネーム後のファイル名は printf で4桁の数字のファイル名を生成しています。

■ 桁数を揃えてリネームする例 (正解例)

とりあえず先ほどの例ではリネームできましたが、ファイル名にハイフンが入ったままで気持ちが悪いです。またリネームしてあげてもよいのですが、実行するコマンドは少ないに越したことがありません。今度はtestコマンドをつけて、リネーム後のファイルがなければという条件式にマッチした時だけ、抜け番を埋めるようにします。勿論わざわざアンダーバーをハイフンにせず実行できます。というわけでまたまたechoで確認です。

コマンドの構文が期待どおりなので、実行してみましょう。なお、shコマンドには -x をつけると処理の中身を見ることができます。

ご覧のように、22番目のファイルまでは何もしていません。23番目のファイルが抜け番なので、24番目のファイルを23番にリネームしています。このように1つでも抜け番があれば、どんどんファイル名の数字を詰めていくので、以降のファイルはすべてリネームしています。また、2番目の抜け番もこのようによろしくやってくれています。

リネーム前のファイル名は、そもそも存在しないファイル名が変数に入りません。また、リネーム後のファイル名は、forループで前回実行した回のリネーム後のファイル名に1を足しているので、上書きの心配もありません。

それではなぜtestコマンドで条件式をつけているのでしょう。その理由ですが、mvコマンドでエラーを出さないためです。testコマンドなしで実行したときはこうなります。

エラーで止めずにすすめたいという乱暴な考えなら一応動きますが、エラーで止める処理がある場合はこうなります。

ご覧のように、mvコマンドのエラーで処理が止まりました。なので、testコマンドの条件式が有用だということがおわかりいただけたかと思います。わざわざshに渡すときにエラーチェックしなくてもいいじゃんと言われればそれまでですが、仮にシェルスクリプトに書く場合、後続の処理を力技ですすめるの怖くないですか?なので、ここまですれば「一応動く」ではなく、「mvコマンドが出すエラーもちゃんとケアして」リネームできたと言えることになります。それではよい画像収集ライフを!