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

perladdict has asked for the wisdom of the Perl Monks concerning the following question:

Hi Monks,

I am trying to prefix a string (reference_)to all the *.bmp files in all the directories as well sub directories. At first time when we run silk script it will creates directries as well subdirectries,under each subdirectories it will stores each mobile application's sceenshot with .bmp extension.
.when i run the automated silkscript for second time it will again creates *.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
Image C:\Image_Repository\BG_Images\second and C:\Image_Repository\BG_Images\sixth having first_screen.bmp and first_screen.bmp files etc...,could any one help me out how can i prefix all the imagefiles with "reference_" string
.When i run the script for second time perl script in silk will take both the images from the subdirectory and compairs the both pixel by pixel.I am trying with below code, could u please guide me 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 actully its not updating files in the subdirectories.

Replies are listed 'Best First'.
Re: How to prefix a string to all the files in a directories as well subdirectories
by ikegami (Patriarch) on Dec 29, 2008 at 11:01 UTC

    I am trying to prefix a string (reference_)to all the *.bmp files in all the directories as well sub directories.

    Correct me if I'm wrong, but you want to prefix the name of the files with "reference_", not the files themselves.

    I tried open call with '+<' mode but i am getting compilation error for the read and write mode.

    opendir(D,"+<$dir1") wouldn't result in a compilation error. It would result in a run-time error because it won't find the directory you named. "+" and "<" aren't even legal characters for directory names in Windows. readdir. You code has other problems, but I won't go into detail since I'm going to recommend that you use File::Find::Rule or similar.

    use strict; use warnings; use File::Find::Rule qw( ); use Path::Class qw( file ); for ( File::Find::Rule->name( '*.bmp' ) ->file() ->in( $dir ); ) { my $file = file($_); my $o = $file; my $n = $file->dir()->file( 'reference_' . $file->basename() ); if (-e $n) { warn("$n already exists\n"); next; } if (!rename($o, $n)) { warn("Unable to rename $o: $!\n"); next; } }
Re: How to prefix a string to all the files in a directories as well subdirectories
by cdarke (Prior) on Dec 29, 2008 at 11:01 UTC
    Your inner foreach loop needs attention. You are altering the filename to the new filename, but not saving it for the rename. Using "$one" as a variable name it not very descriptive either. I suggest:
    foreach $file (@files) { rename $file,"reference_$file" }
    (Untested)
Re: How to prefix a string to all the files in a directories as well subdirectories
by zentara (Archbishop) on Dec 29, 2008 at 16:06 UTC
    If you are going to be modifying directory names, I suggest you read "perldoc File::Find" and search for the section "finddepth", here is a start at it.
    #!/usr/bin/perl use warnings; use strict; use File::Find; $|++; my $path = '.'; finddepth (\&wanted,$path); sub wanted { return unless -d; #-d for dir ops -f for files or comment out for bo +th return $File::Find::prune = 1 if $File::Find::name eq '.'; print "$_\n"; print "$File::Find::name\n"; } __END__

    I'm not really a human, but I play one on earth Remember How Lucky You Are
Re: How to prefix a string to all the files in a directories as well subdirectories
by Anonymous Monk on Dec 29, 2008 at 11:05 UTC
    opendir is not open, you cannot write to dirhandle
    my $newname = "reference_".$filename ; if(not rename $filename, $newname ){ warn "Error renaming $filename to $newname : $!"; }
Re: How to prefix a string to all the files in a directories as well subdirectories
by leocharre (Priest) on Dec 29, 2008 at 20:52 UTC

    What you need to do is rename the files and dirs by order of depth reverse.
    What I mean is.. if you have..

    dir/
    dir/file
    dir/dir/file
    

    And you rename dir/ to reference_dir/, now you can't rename the other files anymore, because they no longer reside in dir/ but in reference_dir/

    I tested this out .. needs more testing to be safe.

    #!/usr/bin/perl use strict; use vars qw($VERSION @PATHS); use Getopt::Std::Strict 'dhvp:a:t'; use Cwd; use Carp; use LEOCHARRE::DEBUG; use File::PathInfo::Ext; $VERSION = sprintf "%d.%02d", q$Revision: 1.1.1.1 $ =~ /(\d+)/g; init(); PATH: for my $abs (@PATHS){ my $f = File::PathInfo::Ext->new($abs) or die; # WHAT IS THE NEW FILENAME my $new_filename; $new_filename .= $opt_p if $opt_p; $new_filename .= $f->filename_only; $new_filename .= $opt_a if $opt_a; $new_filename .= '.'. $f->ext if $f->ext; debug("new filename : $new_filename"); # IS IT THE SAME AS OLD ONE if( $new_filename eq $f->filename ){ warn("same"); next PATH; } my $newpath = $f->abs_loc .'/'.$new_filename; debug("old: $abs, new $newpath"); $opt_t and next PATH; my $newloc = $f->rename( $new_filename ); debug("renamed to $newloc"); } exit; sub usage { qq{$0 - prepend or append filenames OPTIONS -d debug on -h help -v version and exit -p string prepend -a string append, before ext -t test only, don't do it AUTHOR Leo Charre leocharre at cpan dot org SEE ALSO }} sub init { $opt_t and $opt_d = 1; $::DEBUG = 1 if $opt_d; $opt_h and print usage() and exit; $opt_v and print $VERSION and exit; my $abs_path= Cwd::abs_path($_[0]) or die('missing arg or cant reso +lve'); debug("base path: $abs_path"); @PATHS = reverse split( /\n/, `find '$abs_path'` ); @PATHS and scalar @PATHS or die("nothing here"); }
      Hi leocharre, Thanks for your quick reply.
      I am not intended to rename directories as well sub directories, all of these directories and subdirectories stores mobile application screen shot in .bmp files with name first_screen.bmp in all directoris. Only thing i want to prefix a string
      "reference_" to all of these files recursively.Can u help me out how efficianlty i can prefix a string to all these files.Thanks in advance for your reply.
        Like this:
        #!/usr/bin/perl use strict; use warnings; use File::Find; sub callback { my $file = $_; rename $file,"reference_$file" if -f $file } my $dir = 'C:/Image_Repository'; find (\&callback, $dir);
        Of course, there is always More Than One Way To Do It, so you can "hand craft" it if you enjoy lots of typing, but it probably won't be as efficient as using File::Find.
Re: How to prefix a string to all the files in a directories as well subdirectories
by dk (Chaplain) on Dec 31, 2008 at 18:44 UTC
    I've been using Ilya Zakharevich's pfind for similar purposes. For your case,

    pfind . 's/^/reference-/'

    should be enough