再帰的にディレクトリをたぐるperlスクリプト

perlはたまに使うのだけれどなかなか関数を覚えていない。openとかopendirとか使うたびに引数の渡し方を調べている気がする。ウェブ上に残しておく方が後で検索しやすいので残しておく

# 指定したディレクトリのファイル名から' ()'を取り去りアンダースコアに置き換える
# 再帰的に実行する

use strict;

# 終了ステータスメッセージ
my @endStatus = (
    "ファイル名変更に失敗しました。%s=>%s\n" , # 0 失敗の時 Cと逆だ;p)
    "ファイル名を変更しました。%s=>%s\n"       # 成功の時
);

# メインルーチン開始
my $DIR = $ARGV[0];

subRename($DIR);

print "完了!\n";

# メイン終わり

# =============== サブルーチン定義 ==================
# 再帰的にディレクトリをたどりファイル名の' ()'を'_'に置き換える
sub subRename($)
{
    my $hDir = $_[0];
    
    opendir(DIR, "$hDir") or die "ディレクトリ $hDir が開けません。プログラムは死ぬです。\n";
    # 先頭が.で始まるファイル以外を配列に取り込む
    my @directories = grep !/^\./, readdir DIR;
    closedir(DIR);
    
    # ループ内の作業変数宣言
    my ($oldName, $newName, $status);
    for $oldName (@directories) {
        $newName = $oldName;
        $newName =~ s/[ ()]/_/g; # ' ()'を'_'に置き換える
        
        # ファイル名に数字が含まれる場合は0詰め3桁に正規化。
        # 数字は一つしかない前提(初めに現れる数字のみ対象)
        if ($newName =~ /(\d+)/) {
            $newName = sprintf "%s%03d%s", $`, $1, $';
        }
        
        # ディレクトリ名を付加
        $newName = $hDir . '/' . $newName;
        $oldName = $hDir . '/' . $oldName;

        if (-d $oldName) {
            # ディレクトリなら再帰で実行
            subRename($oldName);
        } 

        # リネームの必要が無ければ次へ
        next if ($newName eq $oldName);

        # ファイル名変更
        $status = (rename $oldName, $newName) ? 1 : 0;
        printf $endStatus[$status], $oldName, $newName;
    }
}

__END__