Link to home
Create AccountLog in
Avatar of rark
rark

asked on

how recursively find and rename all files ending in .txt to .oldtxt

how do i recursively search a directory for all files ending in .txt?
then how do i rename them all to .oldtxt?
in shell
Avatar of Jason Minton
Jason Minton
Flag of United States of America image

So you want to do this in a shell script, instead of Perl?  

In Shell you do a little loop like this on the command line or you can put it into a file and run the file:
FRINK:/u/home/jminton> find . -type f |grep \.txt$ | sed "s/\.txt//" | while read file
> do
> mv $file.txt $file.oldtxt
> done

If you want it in perl, let me know -- it's a little more involved.
Avatar of Adam314
Adam314

In shell:
   find /path/to/files -type f -name \*.txt -exec mv \{\} \{\}.oldtxt \;

Avatar of ozo
perl -MFile::Find -e 'find(sub{-f && ($o=$_)=~s/\.txt$/.oldtxt/ && rename $_,$o},"."'
This should do it in PERL

pass the initial starting directory to it like:
recursiveRename.p </home/myname/something  (no trailing slash)

#!/usr/bin/perl

use strict;

my $start = $ARGV[0];

opendir (STARTDIR, $start) or die "Can't start in $start. $!";
while (my $file = readdir(STARTDIR))
{
   findIt("$start");
   next if ($file =~ m/^\.$|^\.\.$/);
   next if (! -d "$start/$file");
   findIt("$start/$file");
}
closedir(STARTDIR);

exit;

################################################################################
sub findIt($)
{
   my $dir = shift;

   opendir (DIR, $dir) or die "Can't open $dir. $!";
   while (my $file = readdir(DIR))
   {
      next if ($file =~ m/^\.$|^\.\.$/);

      # do recursion if this file is a dir
      findIt("$dir/$file") if (-d "$dir/$file");

      if ($file =~ m/(.+)\.txt$/i)
      {
         if (rename("$dir/$file", "$dir/$1.oldtxt"))
         {
            print "Renamed $file to $1.oldtxt \n";
         }
         else
         {
            print "Error Renaming $file. $! \n";
         }
      }
   }
   closedir (DIR);

   return;
}
jasonsbytes, you probably want to either localise the dir handle or the list of files so that the recursion doesn't reset the parents dirhandle.
Or just let File::Find take care of it.
#!/usr/bin/perl -w
use strict;
use File::Find;
use Cwd 'abs_path';

find(\&files, abs_path('.'));

sub files {
    if (/\.txt$/i) {
        my ($new_name) = ($File::Find::name =~ /(.+)\.txt$/i);
        $new_name .= ".oldtxt";
        rename($File::Find::name, $new_name) or die "Cannot rename $File::Find::name: $!";
    }
}
thx ozo!
Avatar of rark

ASKER

perl -MFile::Find -e 'find(sub{-f && ($o=$_)=~s/\.txt$/.oldtxt/ && rename $_,$o},"."'

thank you all.
i pasted in ozo's solution. got this

syntax error at -e line 1, at EOF
Execution of -e aborted due to compilation errors.

also, how do i just find recursively all filenames "*.txt" and "*.oldtxt" so that i can verify the changes were made?

thank you
Windows or Unix/Linux?
Avatar of rark

ASKER

suse linux
#!/usr/bin/perl -w
use strict;
use File::Find;
use Cwd 'abs_path';

my ($renamed, $prior, $verified, $missed);

open (LOG, ">files_changed.log") or die;
print LOG "\n******************* Rename stage *******************\n";
find(\&files, abs_path('.'));
print LOG "Renamed $renamed files, found " . ($prior || 0) . " existing *.oldtxt files\n\n";
print LOG "\n******************* Verification stage *******************\n";
find(\&verify, abs_path('.'));
print LOG "Verified $verified files, found " . ($missed || 0) . " misseed *.txt files\n\n";

sub files {
    if (/\.txt$/i) {
        my ($new_name) = ($File::Find::name =~ /(.+)\.txt$/i);
        $new_name .= ".oldtxt";
        rename($File::Find::name, $new_name) or die "Cannot rename $File::Find::name: $!";
        $renamed++;
        print LOG "Renamed\n\t$File::Find::name\nto\n\t$new_name\n\n";
    } elsif  (/\.oldtxt$/i) {
        print LOG "Found $File::Find::name already matching *.oldtxt\n\n";
        $prior++;
    }
}

sub verify {
    if (/\.oldtxt$/i) {
        print LOG "\nFound $File::Find::name matching *.oldtxt\n\n";
        $verified++;
    } elsif  (/\.txt$/i) {
        print LOG "\nMissed $File::Find::name *.txt\n\n";
        $missed;
    }
}
perl -MFile::Find -e 'find(sub{-f && ($o=$_)=~s/\.txt$/.oldtxt/ && rename $_,$o},".")'
ASKER CERTIFIED SOLUTION
Avatar of ozo
ozo
Flag of United States of America image

Link to home
membership
Create a free account to see this answer
Signing up is free and takes 30 seconds. No credit card required.
See answer
Avatar of rark

ASKER

ozo.  bravo!  thank you.
i also replaced txt with TXT, oldtxt with OLDTEXT  and ran it again.  i assume that's fine. am i right?
Avatar of rark

ASKER

thanks to everyone else also