Bashシェルスクリプトで連番付きファイル名の次の連番を算出する

2021-01-21Bash

はじめに

特定のフォルダにファイルが配置されており、これら全てに通し連番が付与されているとします。

例えば、以下のようにゼロフィルされた3桁の通し連番が付与されているようなファイルが可能されている場合などが考えられます。
(ファイル名でソートできるため、このようなケースはよくあるケースかと思います。)

001_xxx.txt
002_xxx.txt
003_xxx.txt
004_xxx.txt
005_xxx.txt
006_xxx.txt
007_xxx.txt
008_xxx.txt
009_xxx.txt
010_xxx.txt
011_xxx.txt
012_xxx.txt
013_xxx.txt
014_xxx.txt
015_xxx.txt

さて、ここで新しいファイルを作成する場合は 016_xxx.txt というファイル名を算出しなければなりませんが、シェルで次の通し連番を算出する方法について考えてみます。

検証環境

$ uname -moi
x86_64 x86_64 GNU/Linux

$ bash -version | head -n 1
GNU bash, version 4.2.46(2)-release (x86_64-redhat-linux-gnu)

準備

まずはテスト環境を用意してみます。

003_xxx.txt から 013_xxx.txt までの11ファイルを作成し、次の通し連番プレフィックスを持つファイルを作成してみます。

$ touch {003..013}_xxx.txt

$ ls -la
total 4
drwxr-xr-x 13 root root  416 Sep 24 12:59 .
drwxr-xr-x  1 root root 4096 Sep 24 12:59 ..
-rw-r--r--  1 root root    0 Sep 24 12:59 003_xxx.txt
-rw-r--r--  1 root root    0 Sep 24 12:59 004_xxx.txt
-rw-r--r--  1 root root    0 Sep 24 12:59 005_xxx.txt
-rw-r--r--  1 root root    0 Sep 24 12:59 006_xxx.txt
-rw-r--r--  1 root root    0 Sep 24 12:59 007_xxx.txt
-rw-r--r--  1 root root    0 Sep 24 12:59 008_xxx.txt
-rw-r--r--  1 root root    0 Sep 24 12:59 009_xxx.txt
-rw-r--r--  1 root root    0 Sep 24 12:59 010_xxx.txt
-rw-r--r--  1 root root    0 Sep 24 12:59 011_xxx.txt
-rw-r--r--  1 root root    0 Sep 24 12:59 012_xxx.txt
-rw-r--r--  1 root root    0 Sep 24 12:59 013_xxx.txt

次に作成したいファイル名は 014_xxx.txt となります。

新しい通し連番ファイル名を算出する

以下のようなコマンドで、次の通し連番を算出することができます。

# 次の通し連番地を算出(ゼロフィルされていない)
$ LATEST_INDEX=$(
  {
    echo 0
    find . -maxdepth 1 -type f | xargs -n 1 --no-run-if-empty basename | sed 's/^0\+//; s/[^0-9].*$//;'
  } | sort -nr | head -n 1
)

# 3桁でゼロフィルした値をプレフィックスとして付与
$ printf "%03d_xxx.txt" $((LATEST_INDEX + 1))
014_xxx.txt

想定通りのファイル名が取得できました。

ファイルが存在しない場合を考慮し、 echo 0 を実行しています。
これにより必ず最新のINDEX( LATEST_INDEX=0)が取得できるようになります。
ファイルが存在した場合には、ファイル名の先頭に登場する数値以外を除去しておきます。また先頭の0は除去しておきます。(8進数として認識されないようにするための考慮。)

後は取得できた値に1を加算すればよいわけです。

ひとこと

もう少しスマートにロジックを組めないものか。

2021-01-21Bash