Zero pad rename e.g. Image (2).jpg -> Image (002).jpg
I need to rename al开发者_如何学JAVAl 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.- 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. - You can build a better
rename
tool for Cygwin with this shell script usingsed
. - The Windows equivalent for
pwd
is simplycd
. - 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.
- The pad_left sub may not be a better alternative to printf syntax, but it works.
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'
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);
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.
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.
精彩评论