http://www.perlmonks.org?node_id=131861

JoeCool has asked for the wisdom of the Perl Monks concerning the following question: (directories)

I recently D/L a bunch of file and instead of renaming every file in the directory and sub directory manually. I have tried to input a dir and rename all files in that and sub to lc... Please Advise, Joe

Originally posted as a Categorized Question.

  • Comment on How to rename to lowercase every file in a directory and its subdirectories?

Replies are listed 'Best First'.
Re: How do u rename every file in a dir and sub?
by rob_au (Abbot) on Dec 14, 2001 at 08:59 UTC
    This code performs this task for you - It makes use of File::Find to find entries within the given path, ensures that they are actually files (stat and -f _) and then renames them. This could be made more precise by added exclusion matches. eg. return unless (m/\.mp3$/);

    #!d:/perl/bin/perl -w use File::Find; use strict; find ({ 'wanted' => \&renamefile, }, '/path/to/sub/directory'); sub renamefile { my ($dev, $ino, $mode, $nlink, $uid, $gid); return unless (($dev, $ino, $mode, $nlink, $uid, $gid) = lstat($_) +); return unless (-f _); rename $_, lc($_); }
Re: How do u rename every file in a dir and sub?
by robin (Chaplain) on Dec 15, 2001 at 02:34 UTC
    If you're using a Unix system (e.g. Linux or Solaris) then the easiest way is not entirely Perl, but uses the find command to get the filenames, and Perl for the actual renaming:

    find . -type f -exec \ perl -e 'rename($_, lc) || warn "$_: $!\n" for @ARGV' {} \;

    That turns all the filenames in the current directory and below to lower case. If you're using a system which doesn't have the find command, you can use the find2perl utility (it comes with Perl) to generate a Perl script which will behave the same way. On Windows you can type:

    find2perl . -type f -eval "rename $_, lc or warn qq{$_: $!\n}"

    and then run the script that it outputs.

Re: How to rename to lowercase every file in a directory and its subdirectories?
by Anonymous Monk on Sep 25, 2004 at 21:32 UTC
    I'm no perl monk, but here's a tiny extension to Robin's answer, which also changes directory names to lowercase. A script which has just saved my skin.
    #!/usr/bin/perl -w use strict; my $path_to_dir = shift; dir("$path_to_dir"); sub dir { rename "$_[0]","\L$_[0]"; $_[0]="\L$_[0]"; opendir(DIR,"$_[0]"); my @list_of_files = readdir(DIR); foreach(@list_of_files) { if($_ ne "." && $_ ne "..") { if(-d "$_[0]/$_") { dir("$_[0]/$_"); } else { rename "$_[0]/$_","$_[0]/"."\L$_"; } } } }

      rename "$_[0]","\L$_[0]";

      This fails if the lowercase version of the directory already exists and is not empty.
      Maybe worse is, it removes an existing but empty directory of the lowercase name.

      So best to think about a warning:

      unless ( -e "\L$_[0]" ) { rename "$_[0]","\L$_[0]"; } else { warn qq(been too afraid to move "$_[0]" to "\L$_[0]\E" - a file of + that name already exists.\n); }

      Edit:
      One further thought: the script might save some time skipping the renaming
      if the original file or directory already is all-lowercase.

      Cheers, Sören

Re: How do u rename every file in a dir and sub?
by JPaul (Hermit) on Dec 14, 2001 at 05:34 UTC
    One way to do it would be something like this:
    #!/usr/bin/perl -w use strict; # Open 'find' process to list files recursively with paths open(FIND, "find |"); while(<FIND>) { chomp; next if $_ eq $0; # Don't rename ourself rename($_, lc($_)); } close(FIND);
    It's not remarkably efficient, but it'll do your bidding.

    JP

Re: How to rename to lowercase every file in a directory and its subdirectories?
by Alex the Serb (Monk) on Dec 20, 2001 at 19:03 UTC
    you have to use recursion, because you dont know how much deep all subdirectories goes
    #!/usr/bin/perl -w use strict; my $path_to_dir = shift; dir("$path_to_dir"); sub dir { opendir(DIR,"$_[0]"); my @list_of_files = readdir(DIR); foreach(@list_of_files) { if($_ ne "." && $_ ne "..") { if(-d "$_[0]/$_") { dir("$_[0]/$_"); } else { rename "$_[0]/$_","$_[0]/"."\L$_"; } } } }
      Pretty much the idea, but you seem a little confused by variables. Lightly edited (changed to a print statement to protect my innocent file names), here is your code:
      #!/usr/bin/perl use strict; use warnings; dir('.'); sub dir { opendir( DIR, shift ); my @list_of_files = readdir(DIR); foreach (@list_of_files) { if (-d $_) { dir($_) if $_ !~ /^\.\.?$/; } else { print $_," would become \L$_,\n"; } } }
      Things to note:
      • If you mean to use a variable as a parameter, just do it, don't embed it in quotes
      • Your use of $_[0] isn't needed, easier way to do the same is shown
      • Post conditions and regexs are your friend, use them and they will reward you!

      –hsm

      "Never try to teach a pig to sing…it wastes your time and it annoys the pig."
      hsmyers - I cannot reliably make your code work. While the print function appears to show what was intended, it does not properly recurse through, not will it rename the files. However, Alex's code does give the intended results.
Re: How to rename to lowercase every file in a directory and its subdirectories?
by Anonymous Monk on May 17, 2002 at 19:57 UTC
    Simple, Safe, Fast, One-Line Solution
    =============================================
    To combine all the ideas into a safe, but fast, solution that won't overwrite existing files without warning, use:

    find . -type f | perl -ne 'chomp; $src=$_; $lc = lc $src; if ($src ne $lc) { if (-e $lc) { print STDERR "Cannot lc $src (file $lc exists)\n"; } else { rename($src, $lc) || warn "$src: $!\n"; }}'

    Notice the absence of "-exec" option for find. Using "-exec" causes one process for every file found (very slow).

    This code snippet was quite useful at http://www.CleanFunny.com/, where many images originally used random naming conventions.

    Cheers,
    Vess Consulting
    www.vess.com

    Originally posted as a Categorized Answer.

Re: How to rename to lowercase every file in a directory and its subdirectories?
by crazyinsomniac (Prior) on Oct 28, 2002 at 08:22 UTC

    Re: How to rename to lowercase every file in a directory and its subdirectories?

    Originally posted as a Categorized Answer.

Re: How to rename to lowercase every file in a directory and its subdirectories?
by Anonymous Monk on Oct 27, 2002 at 23:51 UTC
    Hmmm .. the "find . -type f" from the CleanFunny guy does recurse through the subdirectories ..

    Originally posted as a Categorized Answer.