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

Hello Monks, I want to rename subdirectories based on the content of some files in that directory. On GNU/Linux I have it working, but MS Windows fails: no rename is done. The depth of the tree is arbitrary, but the name of the directory containing the file needs to be changed. There are no directories in the directory that needs a name-change. Can anyone help? The failing code (cut to the bare essentials):
#!/usr/bin/perl use File::Find; use File::Copy; sub FindData { my $fulldir = $File::Find::dir; my $filename = $File::Find::name; ... open( IN, "<$filename" ) || die "cannot find $filename \n"; .... close IN; if ($olddir ne $newname) { move( "$basedir/$olddir", "$basedir/$newname" ); } } } finddepth( {wanted=>\&FindData,no_chdir}, @path );
Thank you very much

Replies are listed 'Best First'.
Re: renaming subdirectories on MS Windows
by roboticus (Chancellor) on Nov 03, 2010 at 20:41 UTC

    momo33:

    You'll probably have to cache the renames, and do them after you've traversed the directory tree since Windows isn't going to want to let you rename a directory when a process is using it. Something like this:

    my @renames; ... sub wanted { ... push @renames, [ $old_name, $new_name ]; ... } ... find(...); for (@renames) { move $$_[0], $$_[1]; }

    You may be able to do it using the no_chdir option on File::Find, but I don't know. (File::Find may have the directory open anyway as part of how it works.)

    ...roboticus

    Update: Fixed missing code tag.

      This seems to work: thank you!
Re: renaming subdirectories on MS Windows
by toolic (Bishop) on Nov 03, 2010 at 20:45 UTC
    You can get more information as to why the move failed by checking its RETURN value:
    move( "$basedir/$olddir", "$basedir/$newname" ) or die $!;

    Another piece of generic advice: use strict and warnings

Re: renaming subdirectories on MS Windows
by Jim (Curate) on Nov 04, 2010 at 00:00 UTC
Re: renaming subdirectories on MS Windows
by Anonymous Monk on Nov 03, 2010 at 21:07 UTC
    I've written dozens of these scripts, and am very leery of doing actual renaming in program. I much prefer to generate a shell script to do my renaming, so that I can review it before any actual renaming is done
    mv "one" "two"
    This also avoids the problem you're experiencing on win32, trying to rename a directory while its in use
      that's exactly what i would do. write a perl or whatever script to figure out which directories to rename, and the script generates a shell/batch file of the rename commands. you can review this batch rename commands before actual execution. the directory paths will need to be appropriately quoted to avoid problems.
      the hardest line to type correctly is: stty erase ^H
Re: renaming subdirectories on MS Windows
by locked_user sundialsvc4 (Abbot) on Nov 04, 2010 at 13:01 UTC

    Windows’ directory-traversal routines have never played well with code that manipulates the files or directories in any way.   No matter what language you are using, cache the names first, then troll through the list you’ve built.   This is true no matter what language you’re using, and as far as I know, it has been this way since Windows 3.1 if not earlier.

      No matter what language you are using, cache the names first, then troll through the list you’ve built.

      But you can't do this with Perl. Perl can't read Unicode file names on Windows.

      In general, Perl can't be used to work with folders and files on a Windows files system, even just to read their names, at least not simply and reliably.