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

Dear Monks,
I am trying to write a script that will recursively rename all files AND subdirectories. I can't find anything that rename the directories all in one pass. I can write something that renames subdirectories, however, once they are renamed, the script can no longer transcends the directory. For the task to be completed, I have to run it how ever many times there are levels of subdirectories. Here are the basics of what I have.

use strict; use File::Find; $path = '.'; find(\&pattern, $path); sub pattern { print "$_\n"; rename($_, lc($_)); }

Any help would be appreciated,
Scott

Edit: g0n - code tags

Replies are listed 'Best First'.
Re: rename subdirectories
by merlyn (Sage) on Dec 03, 2007 at 21:26 UTC
    You want "depth", so that it visits the current directory last. See the depth option, or the find_depth routines of File::Find.
      Thanks! It now works like a charm.
Re: rename subdirectories
by RaduH (Scribe) on Dec 03, 2007 at 22:43 UTC
    sub rename($) { my $path = $_[0]; #append a trailing / if it's not there if($path !~ /\/$/) { $path .= '/'; } #loop through the files contained in the directory for my $eachFile (glob($path.'*')) { #if the file is a directory if(-d $eachFile) { #pass the directory to the routine ( recursion ) rename($eachFile); } else { my @strings = split('/', $eachFile); my $fileName = $strings[$#strings]; my $filePath = '/'.join('/', @strings[2..$#strings-1]); system("mv $filePath/$fileName $filePath/\"YourNewNameHere\""); } } }#rename
    This is adapted from a script of mine that browses a directory recursively and does something else to each file but it should work for you (or should be close enough - I have not tested it). The filename is made of the path to it plus its name. This name may identify a file or a directory. If it is a directory go in and do your job there first by renaming the files and then you rename the directory itself as well. If you don't follow this order, you'll end up trying to browse a directory that no longer exists (because you've read it's name but you've also renamed it before you tried to browse it).

    That sample system call is one way of doing it and assumes you're using unix (or cygwin on windows). You can definitely change that or maybe use a Perl package for file handling if the OS is a problem.

    Hope this helps!

      I have not tested it
      I wish you did because it does not work the way you expect, if at all.

      First, you redefine the perl built-in rename. So a call to rename would resolve to CORE::rename(), not the one you just wrote.

      Second, you use neither strict nor warnings, which would have indicated:

      Not enough arguments for rename at line 22, near "$eachFile)"
      since rename takes a list of two elements as input.

      Third, you're using a prototype. Don't. Read When to use Prototypes?, and I quote from a node written by tilly: Prototypes have many silent, nasty and unexpected side-effects..

      Last, and most importantly, it does not work (even after correcting the above errors):

      $ mkdir -p /tmp/654653 $ cd /tmp/654653 $ mkdir -p FOO/BAR $ mkdir -p FOO/TZE $ touch FOO/BAR/BANANA $ touch FOO/BAR/APPLE $ touch FOO/TZE/ORANGE $ perl 654653.pl mv: cannot stat `//654653.pl': No such file or directory mv: cannot stat `/BAR/APPLE': No such file or directory mv: cannot stat `/BAR/BANANA': No such file or directory mv: cannot stat `/TZE/ORANGE': No such file or directory mv: cannot stat `/654653/654653.pl': No such file or directory mv: cannot stat `/654653/FOO/BAR/APPLE': No such file or directory mv: cannot stat `/654653/FOO/BAR/BANANA': No such file or directory mv: cannot stat `/654653/FOO/TZE/ORANGE': No such file or directory
      I don't want to disencourage from sharing your code, I just wish you tested it first. A working solution to the original problem could be:
      use strict; use warnings; use File::Find; my $path = '.'; finddepth(\&pattern, $path); sub pattern { print "$_\n"; rename($_, lc($_)); } __END__
      --
      Andreas
Re: rename subdirectories
by perlfan (Parson) on Dec 04, 2007 at 19:45 UTC
    One of my favorite one-liners does the renaming thing, though I've never tested it it on subdirectories. FWIW:
    find . | perl -ne'chomp; next unless -e; $oldname = $_; s/aaa/bbb/; ne +xt if -e; rename $oldname, $_'