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

Hello All, I am new to Perl and the Perl Monks, but I have a slight problem and could use your help. My company has a bunch of pictures with the file extensions of *.TMB and *.JPG. I would like to write a perl script that will go through and change all the *.TMB's to *T.JPG. The T being their only to remind us that they are thumbnail pictues. Have looked around on the site, but still can't figure it out. Here is what I have so far. Any help would be greatly appreciated.
#!/usr/bin/perl -w use strict; my $dir="."; opendir THUMBS, $dir || die "no such dir"; while (my $Temp = readdir(THUMBS)){ if ($Temp =~ ##Not sure what is needed here { if (rename $TEMP, $1) { print $1; } } } closedir THUMBS;
Prince99 "Too Much Is Never Enough"

Replies are listed 'Best First'.
Re: renaming files
by fundflow (Chaplain) on Jan 04, 2001 at 00:48 UTC
    You want to do something like:
    for (<*>) { if(/\.TMB/i) { $old=$_; s/\.TMB$/T\.JPG/; die "$_ already exists" if (-e $_); rename($old, $_) or die "Failed to rename\n"; } }
    update: added a check for exising file, following lemming's suggestion

      If you change:

          s/\.TMB$/T\.JPG/;

      ...to:

          s/\.TMB/T.JPG/i;

      ...you'll catch all cases of all cases. ;]

      Meanwhile, here's a total treatment with a bit of commentary; it uses some neat grep tricks a friend taught me a while back to narrow the list of files before you start processing. I've only tested it a little but it should be correct.

      Cheers!

      --j

      #!/usr/bin/env perl
      #
      # mvThumbs:
      #   A quick script to move thumbnails
      #
      
      use strict;
      use Cwd;
      
      if (! @ARGV) {
        # We need arguments, durnit!
        warn "${0}: Insufficient arguments\n";
        warn "Syntax: $0 <dirName> ...\n";
        exit(1);
      }
      
      # They may give us directory paths which are relative to where we are,
      # so let's be sure of where we are, eh?
      my $origCWD = cwd();
      
      foreach my $dirName (@ARGV) {
        unless (-d $dirName) {
          warn ">>> $dirName is not a directory ... skipping.\n";
        } else {
          # Can we write here? If not, we may as well skip it
          unless (-w $dirName) {
            warn ">>>> No write permissions in $dirName ... skipping\n";
          } else {
            # Get the list of thumbnails in this directory
            opendir(thumbDir, $dirName);
            my @thumbList = grep /\.TMB$/i, readdir(thumbDir);
            closedir(thumbDir);
      
            # To be lazy about having to construct pathnames, we'll just
            # move to the directory we're working with.
            chdir($dirName);
            print "\nIn directory: $dirName\n";
      
            # Run through the list and rename 'em
            foreach my $thumbFile (@thumbList) {
              my $newFile = $thumbFile;
              $newFile =~ s/\.TMB$/T.JPG/i;
              # You could force the filename into lower or upper case here
              # $newFile = lc($newFile);
              # $newFile = uc($newFile);
              unless (-e $newFile) {
                printf("%-30s => %s\n",$thumbFile, $newFile);
                rename($thumbFile, $newFile);
              } else {
                warn ">>> Can't move $thumbFile => $newFile in $dirName;\n";
                warn ">>>   $newFile already exists. Skipping.\n";
              }
            }
      			
            # Back to home base for the next one
            chdir($origCWD);
          }
        }
      }
      
      print "\nAll done!\n";
      
        Corret about the /i thing.

        Also, instead of filtering out using grep, you can just glob the files that you are looking for by:

        foreach my $thumbFile (glob('*.TMB')) {...}
        (I left the core like the original question, just to make it easy for the guy/gal in the original post)
      Hmmm ... surely you don't actually want to 'die' in the middle of a for loop just because one of your files already happens to have the new extension?

      i.e., if I had apple.TMB and apple.JPG then none of banana.TMB, pear.TMB or wombat.TMB would get renamed...

      Tony

        1. As the (updated) song sais: "This is my script and i'll die if i want to" :)

        2. There wouldn't be a problem with your example as apple.tmp goes to applet.jpg

        Anyway, just as you noticed it, I'm sure that Anonymous Monk that posted the original question will be able to adopt the script to his needs. He didn't specify what to do in such cases so better be safe than sorry.

Re: renaming files
by ryddler (Monk) on Jan 04, 2001 at 01:09 UTC

    This should do the trick for you, and should be cross platform as well (you'll all let me know won't you? ;)

    #!perl -w use File::Copy; while (defined(my $filename = <*.tmb>)) { my $filename_2 = substr($filename,0,length($filename)-4)."t.jpg"; move($filename,$filename_2); }

    personally I would use "_t.jpg" as opposed to "t.jpg" simply because I find it easier to read "pic_t.jpg" over "pict.jpg", but that's just my opinion ;)

    ryddler

      Depends on if you want to group your files by type (thumb|full) or picture name. I personally put these kind of indicators in front of the filename, like "th_filename.ext", or "t_filename.ext" so that they are grouped by type.

      Even if they end up residing in different directories, it's easier on the eyes.

      joecamel

Re: renaming files
by lemming (Priest) on Jan 04, 2001 at 00:49 UTC

    What you can do is do a grep(/\.TMB$/, readdir(THUMBS)) which will give you the list of thumbnail files. Then make sure you don't blow away existing files during your renaming function.

    Quick Update: And use fundflow's regex for changing the name. (A clobber check is still advised. -e for a hint)
Re: renaming files
by Anonymous Monk on Jan 04, 2001 at 01:46 UTC
    Thank you all for your help. It is now working, but only if the file extension is upper case. Prince99 "Too Much Is Never Enough"
      Make your regex case insensitive by adding an i. See perldoc perlre or man perlre.
Sorry, but bash can do it!
by Anonymous Monk on Jan 04, 2001 at 05:38 UTC
      I think DOS can do one better though my memory of syntax may be incorrect.
      C:\> move *.tmb *t.jpg
      Note: this is not suggesting that DOS is better than bash in anyway, I firmly believe that DOS (and windows too, though that isn't under discussion) sucks. :)
        You might want to check Rename files safely which gives the same behavior with some perlish extras.
      Why even use cut, awk, or sed to trim when you could just use the shell parameter replacement "${i%TMB}JPG". But to keep it perl:
      while (<*.TMB>) { my $new = $_; substr($new, -3) = "JPG"; warn "$new already exists", next if -e $new; rename $_, $new or warn "Error renaming $_: $!"; }
      Update: I just saw only the above node when I answered, I now see that except for my first comment on the shell solution, I've posted practically the same code already posted higher up (great minds think alike I suppose) :0)