• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 294
  • Last Modified:

Rename Directories

I have this part of a script to process all my txt files in the subdirectories and I know how to rename the filenames but how to tell the script for example to uppercase the containing folders - $dir1, $dir2, $dir3 or all of them with s/\b(\w)/\U$1/g; and without conflicting with the filename editing.
use strict; 
use warnings; 
use File::Find; 
use File::Spec;
 

find(\&d, "test"); 

sub d { 
       my $fn = $File::Find::name;
       
       my $dir1 = (File::Spec->splitdir($fn))[1];       
       my $dir2 = (File::Spec->splitdir($fn))[2];
       my $dir3 = (File::Spec->splitdir($fn))[3];

       while (<*.txt>) {
           my $filename = $_;
	  s/\b(\w)/\U$1/g;
           rename $filename, $_;
       }

}

Open in new window

0
thebourneid
Asked:
thebourneid
  • 3
  • 2
1 Solution
 
wilcoxonCommented:
As long as you are running that on Windows, it will work fine as Windows is not case sensitive.  However, pretty much every other OS is (so it probably will interfere with file editing/renaming).

The simplest fix to avoid issues would be to add a second call to find after the first.  In one, you handle the directory renames and, in the other, you handle the file editing/renaming.

In general, you don't want to rename the directory in your sub d anyway as the script is currently chdir'd into the directory (which could cause problems).
0
 
thebourneidAuthor Commented:
wilcoxon,

I hate when I make hasty conclusions.
I've created a second sub and tested the script and the folders were renamed but later realized that also all the files in the folders were renamed also. I'm trying to rename only specific folders, in my case $dir3.
How to modify the script to do that task without touching the filenames.
use strict; 
use warnings; 
use File::Find; 
use File::Spec;


find(\&a, "test"); 

sub a { 
       my $fn = $File::Find::name;      
              
       my $dir1 = (File::Spec->splitdir($fn))[1];       
       my $dir2 = (File::Spec->splitdir($fn))[2];
       my $dir3 = (File::Spec->splitdir($fn))[3];
       
       
       $dir3 = $_;
       $dir3 =~ s/\b(\w)/\U$1/g;
       rename $dir3, $_;
      
}

Open in new window

0
 
wilcoxonCommented:
Your sub a is definitely renaming everything.  Do you want to rename $dir1 and $dir2 as well or just $dir3?

For a quick and dirty script to do this, I would do...
use strict; 
use warnings; 
use File::Find; 
use File::Spec;

my %dirs;
find(\&a, "test"); 

foreach my $dir1 (keys %dirs) {
    foreach my $dir2 (keys %{$dirs{$dir1}}) {
        foreach my $dir3 (keys %{$dirs{$dir1}{$dir2}}) {
            my $tmp = $dir3;
            $tmp =~ s/\b(\w)/\U$1/g;
            ## rather than the above, you could probably do this
            ## though it is slightly different if non-space sep.
            # $tmp = join ' ', split /\s+/, $dir3;
            rename $dir3, $tmp or die "could not rename $dir3 to $tmp: $!";
        }
        # repeat here for $dir2 if desired
    }
    # repeat here for $dir1 if desired
}

sub a { 
       my $fn = $File::Find::name;      
              
       my $dir1 = (File::Spec->splitdir($fn))[1];       
       my $dir2 = (File::Spec->splitdir($fn))[2];
       my $dir3 = (File::Spec->splitdir($fn))[3];

       # make sure we are 3 dirs deep
       return unless defined($dir3);

       # store the dir in a hash to avoid dupes
       $dirs{$dir1}{$dir2}{$dir3}++;
}

Open in new window

0
 
thebourneidAuthor Commented:
I decided to test the script, before doing something stupid with my directories, with some folder on my desctop named "dir" and I want to rename it to "dir_temp", but may be I'm missing something because nothing changes.
Am I counting the directories right - this should be $dir4
use strict;  
use warnings;  
use File::Find;  
use File::Spec; 
 
my %dirs; 
find(\&a, "C:/Users/Mimo/Desktop/dir/");  
 
foreach my $dir1 (keys %dirs) { 
    foreach my $dir2 (keys %{$dirs{$dir1}}) { 
        foreach my $dir3 (keys %{$dirs{$dir1}{$dir2}}) { 
		foreach my $dir4 (keys %{$dirs{$dir1}{$dir2}{dir3}}) { 
            my $tmp = $dir4; 
            $tmp =~ s/\b(\w)/\U$1/g;
            $tmp =~ s/dir/dir_temp/g; 	    
            ## rather than the above, you could probably do this 
            ## though it is slightly different if non-space sep. 
            # $tmp = join ' ', split /\s+/, $dir3; 
            rename $dir4, $tmp or die "could not rename $dir3 to $tmp: $!"; 
               } 
        # repeat here for $dir3 if desired 
            } 
    # repeat here for $dir2 if desired 
       }
   # repeat here for $dir1 if desired
}
 
sub a {  
       my $fn = $File::Find::name;       
               
       my $dir1 = (File::Spec->splitdir($fn))[1];        
       my $dir2 = (File::Spec->splitdir($fn))[2]; 
       my $dir3 = (File::Spec->splitdir($fn))[3]; 
       my $dir4 = (File::Spec->splitdir($fn))[4]; 
 
       # make sure we are 3 dirs deep 
       return unless defined($dir4); 
 
       # store the dir in a hash to avoid dupes 
       $dirs{$dir1}{$dir2}{$dir3}{$dir4}++; 
}

Open in new window

0
 
wilcoxonCommented:
I think you're doing it right.  My best advice is to add

print "dirs = ", join("\t", $dir1, $dir2, $dir3, $dir4), "\n";

to sub a.  First, I'd try putting them after the "return unless" and, if that doesn't work, try before the return.

I wonder if the E: gets counted as a dir or something?  I hardly ever code perl for Windows (I use CygWin if I'm on a Windows box).
0

Featured Post

Keep up with what's happening at Experts Exchange!

Sign up to receive Decoded, a new monthly digest with product updates, feature release info, continuing education opportunities, and more.

  • 3
  • 2
Tackle projects and never again get stuck behind a technical roadblock.
Join Now