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

As part of a much larger script I need to rotate thousands of files, ie move each one to the next higher number with a maximum of 10, image.9.jpg is the highest kept. The code probably explains it better, here is what I originally wrote-
my $from_name; my $to_name; if (-e "${to_dir}/${base_name}.jpg"){ for (my $i=8; $i >= 0; --$i){ my $ext = ($i ? ".$i" : ''); $from_name=$to_dir.'/'.$base_name.$ext.'.jpg'; $to_name =$to_dir.'/'.$base_name.'.'.($i+1).'.jpg'; rename_and_log($from_name, $to_name) if (-e $from_name); } }

which works but has to check for the existence of a lot of files which potentially don't exist, ie if the highest file is image.4.jpg it still checks for the existance of 8 down. I tried to refine this a bit and ended up with-

my $from_name; my $to_name; if ( -e "${to_dir}/${base_name}.jpg"){ my $i=0; $i = map { /$base_name\.(\d)\.jpg/; $i=$1 > $i ? $1 : $i } <$base_ +name.?.jpg>; $i = $i > 8 ? 8 : $i; for my $index (reverse (0..$i)){ my $ext = $index ? ".$index" : ''; $from_name =$to_dir.'/'.$base_name.$ext.'.jpg'; $to_name =$to_dir.'/'.$base_name.'.'.($index+1).'.jpg'; rename_and_log($from_name, $to_name); } }

which also works but is not very pretty. So I was wondering if any-one could see a better way?

rename_and_log() does what it says :) Logs the transaction to a file and rename()'s with error checking, unless we are in "test" mode in which case it tells instead of doing.


I was thinking of posting this as a golf exercise but I wasn't sure if a) it was worthy and b) if any code resulting from a golf exercise would be useable in production :-) <- note the smiley!

my $chainsaw = 'Perl';

Replies are listed 'Best First'.
Re: rotating files, is there a better way?
by merlyn (Sage) on Apr 04, 2001 at 08:40 UTC
    my $prefix = "$to_dir/$base_name"; my $suffix = ".jpg"; my @names = "$prefix$suffix"; for (my $i = 0; $i < 10; $i++ ) { push @names, "$prefix.$i$suffix"; last unless -e $names[-1]; } while (@names >= 2) { rename_and_log($names[-2], $names[-1]); pop @names; }

    -- Randal L. Schwartz, Perl hacker

Re: rotating files, is there a better way?
by coolmichael (Deacon) on Apr 04, 2001 at 10:46 UTC
    TMTOWDI - I'd be tempted to use a glob like you did but with a regex. I don't think you need to really use -e
    my $pre="image"; my $post="jpg"; my @files=<$pre.*.jpg>; @files=reverse sort @files; #should work because you don't have image.10.jpg #if you do have image.10.jpg, then you will need to use #image.09.jpg for example foreach (@files) { next unless m/^$pre\.(\d)\.$post$/; #just to be sure rename_and_log($_, "$pre." . ($1 >= 8 ? 9 : $1+1) . ".$post\n"); }
    Sorry it's not very readable, but it should work. I think.

    Update: I like merlyn's solution better.

    the blue haired monk