Renaming lots of files

Every now and then it happens that I want to do some maintenance on the filenames of more than just a couple of files. This might happen because of a stupid renaming action by me and/or Windows XP, or simply the use of a new utility which expects filenames in a certain format. Anyway, rather than renaming hundreds of files manually, I like to use some small Perl scripting for these tasks.

The diamond operator in Perl is very useful for fetching directory contents, also in conjunction wild cards. I almost always use it for these small renaming scripts. The basic layout I use is something like this:

sub scanDir {
    my $dir = $_[0];

    my @files = <$dir/*>;

    foreach (@files)
    {
        $foundFile = $_;
        if (-f $foundFile) { 
            &renameFile($foundFile);
        } else {
            &scanDir($foundFile);
        }
    }
}

sub renameFile {
    my $oldfile = $_[0];

    $newfile = "newfilename";

    rename($oldfile,$newfile);
}


&scanDir('.');

exit;

Of course this isn’t the entire script in its full glory. Usually you’ll want some extra checks to only rename files with a specific name, and the new filename is often based on the old filename.

As you’ll have noticed, the script checks for every entry that it’s found whether it’s a file. If not, it is obviously a directory and the method scanDir is called recursively to make sure files anywhere in the directory tree are being renamed.

Today however, I encountered a problem. A lot of the directories I wanted to be handled had names with spaces in them. (Whether or not that is a good idea is another discussion …). These directories break the script. The easy way to go, of course, is to use quotation marks around the filenames. This makes the part which calls the scanDir method again look like this:

        if (-f $foundFile) { 
            &renameFile($foundFile);
        } else {
            &scanDir("\"" . $foundFile . "\"");
        }

Being happy with this quick solution, I let my script do all the renaming. Much to my surprise, not all directories where handled and therefor not all files that I expected where renamed. Figuring out the cause of this took more time than creating the script, but eventually I found what was the problem. When a directory doesn’t have any spaces in its name, putting quotes around the name causes Perl to not find the directory anymore. Not sure whether this is a bug, but with a small check for this situation, the method scanDir now looks like this:

sub scanDir {
    my $dir = $_[0];

    my @files = <$dir/*>;

    foreach (@files)
    {
        $foundFile = $_;
        if (-f $foundFile) { 
            &renameFile($foundFile);
        } else {
            if ($foundFile =~ m/ /) {
                $foundFile = "\"$foundFile\"";
            }
            &scanDir($foundFile);
        }
    }
}

Case closed, happy renaming!

Laat een reactie achter