2

I need to rename all the images as the title explains in all sub-folders. I'm thinking of extracting with regex the number inside the parenthesis then renaming it. Searching around I saw there are tools like rename and mmv but I couldn't get them to pad-rename the jpgs.

I'll appreciate any advise to tackle my problem.

BTW: is for Windows and I have cygwin bash and perl.

Edit:
Conclusions after experimenting with all the answers.

  1. Cygwin rename is not good, the one I could get to work doesn't accept regex, but definitely a nice option, e.g. by running a Linux VM and mounting a Win SharedFolder.
  2. You can build a better rename tool for Cygwin with this shell script using sed.
  3. The Windows equivalent for pwd is simply cd.
  4. Hugmeir posted a promising solution using Perl 5.13+ which are dev releases, but by the time you may be reading this, probably that will be stable.
  5. The pad_left sub may not be a better alternative to printf syntax, but it works.
Eric Fortis
  • 16,372
  • 6
  • 41
  • 62

4 Answers4

7

The rename command could do that:

rename 's/\d+/sprintf("%03d",$&)/e' *.jpg

With subdirectories:

find . -type f -name \*.jpg -print0|xargs -0 rename 's/\d+/sprintf("%03d",$&)/e'
KARASZI István
  • 30,900
  • 8
  • 101
  • 128
1

The below code was tested on Linux; I don't know what you might have to modify to get it to work in your environment. Furthermore I haven't included any searching of sub-directories for .jpg files; if you'd like me to modify the code in that way, please let me know.

(EDIT: for a sub-directories-wide search, please see the program version further down)

use strict;
use warnings;

sub pad_left {
   my $num = shift;

   if ($num < 10) {
      $num = "00$num";
   }
   elsif ($num < 100) {
      $num = "0$num";
   }

   return $num;
}

my @files = glob "*.jpg";

my @padded_names = map {
                          my $name = $_;
                          $name =~ s/^([\w ]+\()(\d+)\)/$1 . &pad_left($2) .')'/e;
                          $name;
                       } @files;

foreach (0..$#files) {
   rename($files[$_], $padded_names[$_]);
   print "$files[$_] --> $padded_names[$_]\n";
}

The above program renames the files and prints the following:

file(1).jpg --> file(001).jpg
file(2).jpg --> file(002).jpg
file(20).jpg --> file(020).jpg
file(200).jpg --> file(200).jpg

HTH

EDIT: Here is an improved version of the above program - it now also incorporates searching of sub-directories for .jpg files. I know my code is no longer required as by now an answer addressing the sub-directory problem has been given, but hey... :)

use strict;
use warnings;
use File::Find;

sub pad_left {
   my $num = shift;

   if ($num < 10) {
      $num = "00$num";
   }
   elsif ($num < 100) {
      $num = "0$num";
   }

   return $num;
}

sub new_name {
   if (/\.jpg$/) {
      my $name = $File::Find::name;
      my $new_name;
      ($new_name = $name) =~ s/^(.+\/[\w ]+\()(\d+)\)/$1 . &pad_left($2) .')'/e;
      rename($name, $new_name);
      print "$name --> $new_name\n";
   }
}

chomp(my $localdir = `pwd`);# invoke the script in the parent-directory of the
                            # image-containing sub-directories

find(\&new_name, $localdir);
canavanin
  • 2,559
  • 3
  • 25
  • 36
  • wow that was quick! thank you very much. if it doesn't bother you, yes please, help me also with the subdirs. – Eric Fortis Dec 30 '10 at 10:15
  • @Eric Fortis Ok, I'll give it a go :) Just wait a few minutes. – canavanin Dec 30 '10 at 10:16
  • @Eric Fortis Played around with it a bit, took me longer than expected actually >_< The Perl solution's no longer required I guess, but as I had got interested and wanted to get it done I thought I might just as well share the result... – canavanin Dec 30 '10 at 11:02
  • 2
    Why the ugly `pad_left` routine? Is there some reason `sprintf` won't work for you? – sorpigal Dec 30 '10 at 12:49
  • worked great, I just needed to change pwd to cd, since its windows. – Eric Fortis Dec 30 '10 at 19:24
1
perl -MFile::Find::Rule -E 'rename($_, s/ \( \K ([0-9]+) (?= \) ) / sprintf("%03s", $1) /rex) for File::Find::Rule->file->name("*.jpg")->in($ARGV[0])' directory_here

This will only work with 5.13+ Perls though, due to the /r flag.

EDIT: For Windows, you'll have to change the outer quotes with double quotes, and either escape the ones in the sprintf and name, or use a different delimtier, ala qq!%03d!

EDIT2: Woah, totally screwed up my delimiters there.

Hugmeir
  • 1,249
  • 6
  • 9
  • A backwards-compatible version: perl -MFile::Find::Rule -E "for (File::Find::Rule->file->name(q!*.txt!)->in('C:/My Dropbox')) { ( my $newname = $_ ) =~ s/ \( \K ([0-9]+) (?= \) ) /sprintf(qq!%03s!, $1) /ex; rename $_, $newname }" – Hugmeir Dec 30 '10 at 22:12
  • 1
    Here is a link to brian d foy's blog about the new /r flag http://www.effectiveperlprogramming.com/blog/659 – Joel Berger Dec 31 '10 at 05:34
  • @Joel: Any link to The Effective Perler gets a ++. No exceptions. – Hugmeir Dec 31 '10 at 13:31
0

Again on a tangential path, if you're on windows and you goal is to rename files rather than do some programming), try freeware Siren (http://www.scarabee-software.net/en/siren.html) It does exactly what is required, e.g. try the following expression Image \(%N1{3}\).%le. In particular, check out the %X* expressions catering specifically for images.

whjou
  • 156
  • 1
  • 6