ほぼ中立ブログ

少しだけ趣味に偏った雑記ブログ

Pythonでディレクトリ下のファイルを再帰的にリネームして通し番号を振る

pythonでディレクトリ(フォルダ)下のファイルを一括で変更して通し番号を振るスクリプトを作ったので備忘録を兼ねてまとめます。

Windowsでも動くような気はしますが、テストした環境はUbuntu 18.04 LTSです。

目標

以下のような構成のフォルダがあるとします。

$ tree dir1
dir1/
├── a.txt
└── b
    ├── b.txt
    ├── c
    │   └── c.txt
    └── d
        └── d.txt

これを以下のようにリネームするのが今回作りたかったスクリプトです。

$ python rename.py dir1 file
$ tree dir1
dir1/
├── b
│   ├── c
│   │   └── file_3.txt
│   ├── d
│   │   └── file_4.txt
│   └── file_2.txt
└── file_1.txt

要するに、ディレクトリの構造は変えずにファイルだけリネームし、与えられた接頭辞を付けて、通し番号を振りたかったんです。

スクリプト

完成したスクリプトは以下のとおりです。コメントで簡単な解説を入れました。最初は画像ファイルを対象とするつもりだったので変数名がそれに関連したものになってしまっていますが、ファイルの種類にかかわらず動作します。

ただ、globの再帰的なマッチを使用していますので、Python 3.5以降でないと正しく動作しません。

ファイル名の変更はファイルの上書き等によりデータのロストが起こりやすいものですので、お試しになる場合はバックアップを取るなどして自己責任でお願いします。

# rename.py

import glob
import os
import sys

indir = sys.argv[1]
prefix = sys.argv[2]

# ディレクトリ下のファイル名を再帰的に取得する
path = os.path.join(indir, "**/*.*")
all_imgs = glob.glob(path, recursive=True)
all_imgs.sort()
# ファイル数が何桁か調べる
digit = len(str(len(all_imgs)))

for index, img in enumerate(all_imgs, 1):
    # 元のディレクトリ構造とファイル名、拡張子を取得する
    ori_dir, ori_name = os.path.split(img)
    filename, suffix = os.path.splitext(ori_name)
    # 自分自身はリネームしない
    if ori_name == "rename.py":
        continue
    # 通し番号の桁を揃える
    num = str(index).zfill(digit)
    # 新しいファイル名の生成、ディレクトリと拡張子は元のまま
    new_name = "{0}_{1}{2}".format(prefix, num, suffix)
    new_path = os.path.join(ori_dir, new_name)
    # 変更後と同じ名前のファイルが存在する場合はスキップ
    if os.path.exists(new_path):
        sys.stderr.write(
            "{0} already exists\n".format(new_path))
        continue
    # リネーム
    os.rename(img, new_path)
    print("{0} -> {1}".format(ori_name, new_name))