On 24 Nov 2006 at 23:55, D. Bolliger wrote: > Beginner am Freitag, 24. November 2006 14:48: > > Hi, > > > > I have a number of jpegs I wanted to rename. I wrote a short script > > to do it but the new file name is not always generated correctly. The > > script should find the last letter in the filename (before the > > extension) and substitute it for '_a'. > > Hi Beginner > > I assume that you mean "substitue with _a". > > > If you look at the results below you'll see that 'a' and 'b' fail but > > 'c' worked. I don't understand why. > > > > DSC00092a.jpg -> DSC00092a.jpg a > > DSC00093b.jpg -> DSC00093b.jpg b > > DSC00094c.jpg -> DSC00094_a.jpg c > > ...snip > > > > Here the script, there isn't much to it. Can anyone explain why the > > substitute fails? > > I should not mention that in the public ;-) but, just to demonstrate one way > to search for a reason for a malfunction: > > Because I did not see an error at first glance, I... > > > #!/bin/perl > > # Active State 5.8.6.811 > > > > use strict; > > use warnings; > > use File::Basename; > > > > my $dir = 'D:/Temp/jpegs/thumbs/'; > > my @files = glob("${dir}*.jpg"); > > ...replaced these two lines with simply > > my @files=qw(DSC00092a.jpg DSC00094c.jpg); # etc > > and everything worked fine. > Then, I created these files in the current directory, and again everything > worked fine. > > Then, I made a subdirectory, moved the file over, ... > > > > foreach my $f (@files) { > > (my $l) = ($f =~ /([a-z]|[a-z][a-z])\.jpg/); > > (my $new = $f) =~ s/$l/_a/; > > ...placed here a > > warn "new=$new"; > > and got (excerpt): > > new=/home/d_ani/ramsch/thumbs/DSC00092a.jpg at ./script.pl line 17. # !! > new=/home/dani/ramsch/thum_as/DSC00093b.jpg at ./script.pl line 17. # !! > new=/home/dani/rams_ah/thumbs/DSC00094c.jpg at ./script.pl line 17. # !! > new=/home/dan_a/ramsch/thumbs/DSC00100i.jpg at ./script.pl line 17. # !! > new=/home/dani/ramsch/thumbs/DSC00101_a.jpg at ./script.pl line 17. > > > my $basef = basename($f); > > my $basenew = basename($new); > > print "$basef -> $basenew $l\n"; > > } > > And now it's extraordinary obvious that the error is > > (my $new = $f) =~ s/$l/_a/; > > which simply searches for the first char contained in $l and replaces it > with '_a'. This makes the malfunction dependent from the contents in $dir. > > Instead, this line should be more specific, f.ex: > > (my $new = $f) =~ s/$l\.jpg$/_a\.jpg/; > > (Note that I anchor with $ since "DSC00092a.jpg" is a valid path name :-) ) > > Of course it would have been sufficient to only present this last > substitution > to lead you to a "aha!", but I think it's important to have a personal > strategy to search for errors in the dark :-) > > > btw, the foreach code can at least be shortened to: > > foreach my $basef (map basename ($_), @files) { > (my $l) = ($basef =~ /([a-z]{1,2})\.jpg$/); > # above line is still problematic: What if the match failes? > > (my $basenew = $basef) =~ s/$l\.jpg$/_a\.jpg/; > print "$basef -> $basenew $l\n"; > } > > and certainly optimized further in several ways (f.ex if you don't need the > last print statement, $l could possibly be eliminated), but I'm so tired and > brain dead at the time :-)
Thanx Dani and John, I should have realised that the that I was making the substitiution on the full path and not the basename. I appreciate you showing me how to shorten the code. Can I ask if I am reading it right. foreach my $basef (map basename ($_), @files) { (my $l) = ($basef =~ /([a-z]{1,2})\.jpg$/); Does this basename everything in @files and make it $basef? In John's example I am not sure what is happening with this RegEx: ( my $new = $f ) =~ s/([a-z]{1,2})(?=\.jpg\z)/_a/; There are 2 sets of parentheses but one lvalue, $new. So is that any character a-z, 1 or 2 times and the ? mean 1 or more times? What is the \z switch here? I can find it is perlre. Thanx again. Dp. -- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED] <http://learn.perl.org/> <http://learn.perl.org/first-response>