Search code examples
perlfilebatch-rename

How can I add a prefix to all filenames under a directory?


I am trying to prefix a string (reference_) to the names of all the *.bmp files in all the directories as well sub-directories. The first time we run the silk script, it will create directories as well subdirectories, and under each subdirectory it will store each mobile application's sceenshot with .bmp extension.

When I run the automated silkscript for second time it will again create the *.bmp files in all the subdirectories. Before running the script for second time I want to prefix all the *.bmp with a string reference_.

For example first_screen.bmp to reference_first_screen.bmp, I have the directory structure as below:

C:\Image_Repository\BG_Images\second
...
C:\Image_Repository\BG_Images\sixth

having first_screen.bmp and first_screen.bmp files etc...

How can I prefix all the image file names with reference_ string?

When I run the script for second time, the Perl script in silk will take both the images from the sub-directory and compare them both pixel by pixel. I am trying with code below. How can I proceed to complete this task?

#!/usr/bin/perl -w
&one;

&two;

sub one {

    use Cwd;

    my $dir ="C:\\Image_Repository";
    #print "$dir\n";
    opendir(DIR,"+<$dir") or "die $!\n";
    my @dir = readdir DIR;
    #$lines=@dir;
    delete $dir[-1];
    print "$lines\n";
    foreach my $item (@dir)
    {
        print "$item\n";
    }
    closedir DIR;
}

sub two {

    use Cwd;

    my $dir1 ="C:\\Image_Repository\\BG_Images";
    #print "$dir1\n";
    opendir(D,"+<$dir1") or "die $!\n";
    my @dire = readdir D;
    #$lines=@dire;
    delete $dire[-1];
    #print "$lines\n";
    foreach my $item (@dire)
    {
        #print "$item\n";
        $dir2="C:\\Image_Repository\\BG_Images\\$item";
        print $dir2;
        opendir(D1,"+<$dir2") or die " $!\n";
        my @files=readdir D1;
        #print "@files\n";  
        foreach $one (@files)
        {
            $one="reference_".$one;
            print "$one\n";
            #rename $one,Reference_.$one;
        }
    }
    closedir DIR;
}

I tried open call with '+<' mode but I am getting compilation error for the read and write mode. When I am running this code, it shows the files in BG_images folder with prefixed string but actually it's not updating the files in the sub-directories.


Solution

  • You don't open a directory for writing. Just use opendir without the mode parts of the string:

    opendir my($dir), $dirname or die "Could not open $dirname: $!";
    

    However, you don't need that. You can use File::Find to make the list of files you need.

    #!/usr/bin/perl
    use strict;
    use warnings;
    
    use File::Basename;
    use File::Find;
    use File::Find::Closures qw(find_regular_files);
    use File::Spec::Functions qw(catfile);
    
    
    my( $wanted, $reporter ) = find_regular_files;
    find( $wanted, $ARGV[0] );
    
    
    my $prefix = 'recursive_';
    
    
    foreach my $file ( $reporter->() )
        {
        my $basename = basename( $file );
    
        if( index( $basename, $prefix ) == 0 )
            {
            print STDERR "$file already has '$prefix'! Skipping.\n";
            next;
            }
    
        my $new_path = catfile( 
            dirname(  $file ), 
            "recursive_$basename"
            );
    
        unless( rename $file, $new_path )
            {
            print STDERR "Could not rename $file: $!\n";
            next;
            }
    
        print $file, "\n";  
        }