squirell has asked for the wisdom of the Perl Monks concerning the following question:

Real world problem: I have a group of files buried within a hierarchy. They need renaming regardless of their extension by referring an unordered list of name pairs: Old Name and New Name separated by whatever delimiter I want; let's say a comma. I am thinking of a script using the modules file::find and list::Compare, where the list::compare module intersects the list of files reaped from the find::file routine. Am I barking up the right tree or just barking mad? I am really inexperienced at coding perl. I searched a lot before I asked the question here but I don't see anything exactly like what I am saying. Another solution on this site just didn't seem like it would do what I wanted (there was no use of either module) maybe I am making too big a deal out of it. Thanks!
  • Comment on Renaming a group of files by referring to a list

Replies are listed 'Best First'.
Re: Renaming a group of files by referring to a list
by pc88mxer (Vicar) on Dec 11, 2007 at 00:47 UTC
    Perl is the right tool for this job, but given the potential for creating a big mess of things, I would perform the operation in stages:

    1. Generate a list of the files you want to rename.
    2. Generate a list of the renamings you want to perform.
    3. Execute the renamings.

    Then at each stage you can verify that you are going to do what you want to do.

    For step 1, just assemble a list of the relavent file names into a text file, one path per line.

    For step 2, read in the contents of the file generated in step 1 and output another file consisting of pairs of file names.

    For step 3, read in the output of step 3 and execute the renaming.

    E.g.:

    Output of step 1:

    file1 file2 file3

    Output of step 2:

    file1 new-file-1 file2 new-file-2 file3 new-file-3

    Then you can visually inspect the output at each stage to verify that what you want to happen will happen. I always do this before I make big changes to a tree of files.

    The only tricky part is step 2 - you have to decide how to encode a pair of path names into a single line (or use some other encoding). Usually this will require knowing that a certain character, e.g. a space, will not occur in your list of file names. Or perhaps you can use a sequence of characters (like '-->') which you know doesn't occur in your list of file names. So the script for step 2 might look something like:

    while (<>) { chomp; ... derive $new from $_ ... print $_, ' --> ', $new, "\n"; # use ' --> ' as the delimiter }

    and the beginning part of the script for step 3 looks like:

    while (<>) { chomp; my ($old, $new) = split(' --> ', $_, 2); unless (rename $old, $new) { warn "unable to rename $old to $new: $!\n"; } }

    As for how to derive the new names from the old names, that all depends on what kind of renaming you need to perform. Using regular expression or looking up names in a hash are potentially good ways of doing it.

    Generating the files can be done either in perl or with just shell tools like find and grep.

    Hope this helps.

      Thanks! It is good to know I am using the right tool for the job. Thank you for the logical breakdown, too. (And for the helper code) :) I really appreciate the help.
Re: Renaming a group of files by referring to a list
by JStrom (Pilgrim) on Dec 11, 2007 at 02:26 UTC
    If I understand your problem correctly (my reading is: You have a list of files, you have a list of old/new filename pairs, you want to know which files have a corresponding new filename) then this problem just screams HASH.

    A hash lets you index the elements by a string, so rather than searching an array (via List::Compare) for the matching element, you can write things like:

    %rename_hash = ( 'oldname' => 'newname' ); if( exists $rename_hash{ $filename } ) # Does this file get changed? { ... } $newname = $rename_hash{ $filename } # What's the new name? ...
    You might even be able to squeeze all the code into File::Find::find()'s \&wanted parameter (though risky as you'd be changing the data File::Find is looking through).
      I forgot about Hashes! I'll go re-read that chapter for tonight, thanks!