Ad_noob
Ad_noob

Reputation: 73

How to find a specific files recursively in the directory, rename it by prefixing sub-directory name, and move it to different directory

I am perl noob, and trying to do following:

  1. Search for files with specific string in a directory recursively. Say string is 'abc.txt'
  2. The file can be in two different sub-directories, say dir_1 or dir_2
  3. Once the file is found, if it is found in dir_1, rename it to dir_1_abc.txt. If it is in dir_2, then rename it to dir_2_abc.txt.
  4. Once all the files have been found and renamed, move them all to a new directory named, say dir_3

I don't care if I have to use any module to accomplish this. I have been trying to do it using File::Find::Rule and File::copy, but not getting the desired result. Here is my sample code:

#!/usr/bin/perl -sl
use strict;
use warnings;
use File::Find::Rule;
use File::Copy;

my $dir1 = '/Users/macuser/ParentDirectory/logs/dir_1'  
my $dir2 = '/Users/macuser/ParentDirectory/logs/dir_2'  

#ideally I just want to define one directory but because of the logic I am using in IF 
#statement, I am specifying two different directory paths

my $dest_dir = '/Users/macuser/dir_3';
my(@old_files) = find( 
              file => (),
              name => '*abc.txt', 
              in => $dir1, $dir2 ); #not sure if I can give two directories, works with on


foreach my $old_file(@old_files) {

        print $old_file;    #added this for debug

    if ($dest_dir =~ m/dir_1/)       
    {
      print "yes in the loop";
      rename ($old_file, "dir_1_$old_file");
          print $old_file;
          copy "$old_file", "$dest_dir";
    } 

       if ($dest_dir =~ m/dir_2/)       
   {
      print "yes in the loop";
      rename ($old_file, "dir_2_$old_file");
          print $old_file;
          copy "$old_file", "dest_dir";
   } 
   }

The code above does not change the file name, instead when I am printing $old_file inside if, it spits the whole directory path, where the file is found, and it is prefixing the path with dir_1 and dir_2 respectively. Something is horribly wrong. Please help simply.

Upvotes: 1

Views: 354

Answers (2)

CS Pei
CS Pei

Reputation: 11047

If you have bash ( I assume in OSX it is available), you can do this in a few lines (usually I put them in one line).

destdir="your_dest_dir"
for i in `find /Users/macuser/ParentDirectory/logs -type f -iname '*abc.txt'  ` 
do  
    prefix=`dirname $i`
    if [[ $prefix = *dir_1* ]] ; then
        prefix="dir_1"
    fi

    dest="$destdir/${prefix}_`basename $i`"
    mv "$i" "$dest" 
done

The advantage of this method is that you can have many sub dirs under logs and you don't need to specify them. you can search for files like blah_abc.txt, tada_abc.txt too. If you want a exact match just juse abc.txt, instead of *abc.txt.

Upvotes: 0

kjpires
kjpires

Reputation: 740

If the files can be placed in the destination as you rename them, try this:

#!/usr/bin/perl
use strict;

use File::Find;
use File::Copy;

my $dest_dir = '/Users/macuser/dir_3';
foreach my $dir ('/Users/macuser/ParentDirectory/logs/dir_1', '/Users/macuser/ParentDirectory/logs/dir_2') {
    my $prefix = $dir; $prefix =~ s/.*\///;

    find(sub {
        move($File::Find::name, "$dest_dir/${prefix}_$_") if /abc\.txt$/;
    }, $dir);
}

If you need to do all the renaming first and then move them all, you could either remember the list of files you have to move or you can make two passes making sure the pattern on the second pass is still OK after the initial rename in the first pass.

Upvotes: 0

Related Questions