やりたいこと
あるディレクトリ配下に存在する全てのディレクトリを一括でリネームする. 例えば、このようなディレクトリ構造から
.
├── a.txt
├── dir_1
└── dir_2
├── b.txt
├── dir_3
└── dir_4
├── c.txt
├── dir_5
└── dir_6
カレントディレクトリ配下のディレクトリを、以下のようなディレクトリ名に再帰的にリネームしたい.
.
├── a.txt
├── new_dir_1
└── new_dir_2
├── b.txt
├── new_dir_3
└── new_dir_4
├── c.txt
├── new_dir_5
└── new_dir_6
How?
深さ優先探索の要領でディレクトリを探索させることで、最も深い階層のディレクトリから優先的にリネームすることができる.
from pathlib2 import Path
def rename_dirs(path):
path = Path(path)
dirs = [d for d in path.iterdir() if d.is_dir()]
for d in dirs:
rename_dirs(d)
new_name = "new_" + d.name
d.rename(d.parent / new_name)
rename_dirs(".")
rename_dirs()
は、引数のpath直下にあるサブディレクトリを列挙してから、それぞれのサブディレクトリに対しさらに直下のサブディレクトリを列挙する(再帰処理).これを繰り返し、サブディレクトリをもたないディレクトリまでたどり着いたときに、そのディレクトリのリネームが行われる.また浅い階層(=最下層ではない)ディレクトリのリネームは、自分のサブディレクトリが全てリネームされた段階で逐次実行されることになる.
Appendix
参考までに、pathlibモジュールのglob()
を使ってうまくいかなかった例を残しておきます. (glob()
の引数**
を指定すると、再帰的にディレクトリだけ取得できます.)
from pathlib2 import Path
path = Path(".")
dirs = [d for d in path.glob("**") if not str(d)=="."] #カレントディレクトリをレネーム対象から除いておく
for d in dirs:
new_name = "new_" + str(d.name)
d.rename(d.parent / new_name)
FileNotFoundError: [Errno 2] No such file or directory: './dir_2/dir_4' -> './dir_2/new_dir_4'
「そんなファイルないよ」と怒られます.リネームのループ中で、浅い階層にあるディレクトリのリネームを、それより深い階層にあるディレクトリのリネームより前に行ってしまったからです.dir_2
がnew_dir_2
と変名されると、次のループで処理対象となるdir_2/dir_4
はもう存在しません.(存在するのはnew_dir_2/dir_4
)