# renner Copyright (c) 2007 Doug Mayo-Wells. # V 1.0.01, November 2007 # Permission is hereby granted, free of charge, to any person obtaining a copy of this software and # associated documentation files (the "Software"), to deal in the Software without restriction, # including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, # and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, # subject to the following conditions: # # The above copyright notice and this permission notice shall be included in all copies or substantial # portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, # INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR # PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR # OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER # DEALINGS IN THE SOFTWARE. #!/usr/bin/perl $argcount = @ARGV; # set up defaults! very important. $verbose = $test = $recurse = $actondir = 0; $mask = $unmask = $substitute = $append = $prepend = ""; $unprepend = $unappend = $digmin = $digest = 0; # process arguments $flag=""; for ($i=0; $i<$argcount ;$i++) { $this = $ARGV[$i]; #print ("argument $i+1 is '$ARGV[$i]'\n"); # set flags or show help if ($ARGV[$i] =~ /-help/) { &help; } elsif ($ARGV[$i] =~ /-v/) { $verbose = 1; print ("Verbose mode.\n"); } elsif ($ARGV[$i] =~ /-silent/) { $verbose = 0; print ("Silent mode.\n"); } elsif ($ARGV[$i] =~ /-test/) { $test = 1; print ("Test mode.\n"); } elsif ($ARGV[$i] =~ /-r/) { $recurse = 1; print ("Recursive mode.\n"); } elsif ($ARGV[$i] =~ /-dir/) { $actondir = 1; print ("Act on directories.\n"); } elsif ($ARGV[$i] =~ /-mask/) { $mask = &doSpecialArgs($ARGV[$i+1]); print ("Set mask '$mask'\n"); } elsif ($ARGV[$i] =~ /-unmask/) { $unmask = &doSpecialArgs($ARGV[$i+1]); print ("Set mask '$unmask'\n"); } elsif ($ARGV[$i] =~ /-sub/) { $substitute = &doSpecialArgs($ARGV[$i+1]); print ("Set substitute '$substitute'\n"); } elsif ($ARGV[$i] =~ /-dig/) { $digmin = $ARGV[++$i]; $digset = $ARGV[++$i]; $zdif = $digset - $digmin; for ($k=0;$k<($digset - $digmin);$k++) { $zpad = $zpad . "0"; } print ("Zero pad $zpad strings of $digmin digits to $digset\n"); } elsif ($ARGV[$i] =~ /-app/) { $append = &doSpecialArgs($ARGV[$i+1]); print ("Set append '$append'\n"); } elsif ($ARGV[$i] =~ /-pre/) { $prepend = &doSpecialArgs($ARGV[$i+1]); print ("Set prepend '$prepend'\n"); } elsif ($ARGV[$i] =~ /-unpre/) { $unprepend = $ARGV[$i+1]; print ("Set unprepend '$unprepend'\n"); } elsif ($ARGV[$i] =~ /-unapp/) { $unappend = $ARGV[$i+1]; print ("Set unappend '$unappend'\n"); } } #exit(0); if ($argcount>0) { $seed_dir = $ARGV[0]; } else { # start where we're at &shorthelp(); #$seed_dir = "."; } if (($mask eq "")&&($unmask eq"")) { print ("default mask\n") if ($verbose); $mask = "."; } $foundcount = 0; $renamecount = 0; # recurse! @dirlist = ($seed_dir); &dirproc; print ("\nDone. Found $foundcount and renamed $renamecount files.\n") if (!$silent); exit; sub dirproc { # pop last from the stack $thisdir = pop(@dirlist); print ("\n$thisdir") if ($verbose); print ("<") if (!$silent); #($thisdir)"); $filecount = 0; # there's problem where sometimes a file is renamed and then shows up again later in the directory stack. # 'solve' by reading whole file list into memory at once. opendir (THISDIR, $thisdir); # no . or .. , straight from the camel @allfiles =grep !/^\.\.?$/, readdir THISDIR; closedir (THISDIR); #opendir(THISDIR, $thisdir ); foreach $filename (@allfiles) { #while ($filename = readdir(THISDIR) ) # { $testpath = $thisdir . "\\" . $filename; #//print ("$testpath"); #//print ("\n$filename") if ($verbose); print (".") if ($verbose); # don't push "." or ".." !!! if (($filename eq "." || $filename eq "..") ) { # special file, do nothing print (" (skipping $filename) ") if ($verbose); } elsif ((-d $testpath) & ($recurse)) { # directory, push print (" (pushing $filename) ") if ($verbose); push (@dirlist,$testpath); } elsif ((-d $testpath) & (!$actondir)) { # directory, do nothing print (" (skipping directory $filename) ") if ($verbose); } elsif (($mask ne "")||($unmask ne "")) { #//print ("\nmask: $filename") if ($verbose); if ($mask ne "") { $flag = ($filename =~/$mask/); } else { $flag = !($filename =~/$unmask/); } if ($flag) { ++$foundcount; print ("match: $match $filename\n") if ($verbose); $targname = $filename; if ($unappend > 0) { $targname = substr($targname,0,length($targname)-$unappend); } if ($unprepend > 0) { $targname = substr($targname,$unprepend,length($targname)-$unprepend); } if ($digmin > 0) { if ($targname =~ /\D\d{$digmin}\D/) { print ("parametized match \n") if ($verbose); $targname =~ s/(\D)(\d{$digmin})(\D)/\1$zpad\2\3/g; } # check start of filename too elsif ($targname =~ /^\d{$digmin}\D/) { print ("parametized match at start\n") if ($verbose); $targname =~ s/^(\d{$digmin})(\D)/$zpad\1\2/g; } elsif ($targname =~ /\D\d{$digmin}$/) { print ("parametized match at end\n") if ($verbose); $targname =~ s/(\D)(\d{$digmin})$/\1$zpad\2/g; } elsif ($targname =~ /^\d{$digmin}$/) { print ("parametized match whole file\n") if ($verbose); $targname =~ s/^(\d{$digmin})$/$zpad\1/g; } } if ($append ne "") { $targname = $targname . $append; } if ($prepend ne "") { $targname = $prepend . $targname; } if ($substitute eq "nul") { $targname =~ s/$mask//g; } if ($substitute ne "") { $targname =~ s/$mask/$substitute/g; } if ($targname ne $filename) { &reename($thisdir); } else { print ("matched; not changed \n") if ($verbose); } } } else { print (" = plainfile\n") if ($verbose); } } #closedir(THISDIR); # are we done? $count = @dirlist; if ($count>0) { &dirproc; } return; } sub reename { local ($ltdir) = @_; local $ltarg = $ltdir . "\\" .$targname; local $lname = $ltdir . "\\" . $filename; if (-e $ltarg) { print (" $lname, $ltarg exists \n"); } else { print (" $lname -> $ltarg \n"); ++$renamecount; if ($test) { print(" --test-- "); } else { rename($lname,$ltarg); } } } sub doSpecialArgs { local ($string) =@_; $string =~ s/\$space/ /g; return $string; } sub shorthelp{ $t = "Batch file renming utility\n\n"; $t .= " renner.pl location [matchcriterion] action [utility]\n\n"; $t .= "match criteria:\n"; $t .= " -mask S|-unmask S\n"; $t .= " -dir\n"; $t .= "action:prepend/append/truncate:\n"; $t .= " -app S| -pre S| -unapp n| -unpre n\n"; $t .= "action:filename substitutions:\n"; $t .= " -mask S1 -sub S2\n"; $t .= " -dig n1 n2\n"; $t .= "recursion:\n"; $t .= " -r\n"; $t .= "utility:\n"; $t .= " -help | -silent | -test | -v\n"; $t .= "EXAMPLE:\n"; $t .= "Add .jpg to all non jpg files\n"; $t .= " renner . -unmask jpg\$ -app .jpg\n"; print $t; exit } sub help { $t = "\nBatch file renming utility\n\n"; $t .= " renner.pl location [matchcriterion] action [utility]\n\n"; $t .= "match criteria:\n"; $t .= " -mask S|-unmask S\n"; $t .= " -dir\n"; $t .= "action:prepend/append/truncate:\n"; $t .= " -app S| -pre S| -unapp n| -unpre n\n"; $t .= "action:filename substitutions:\n"; $t .= " -mask S1 -sub S2\n"; $t .= " -dig n1 n2\n"; $t .= "recursion:\n"; $t .= " -r\n"; $t .= "utility:\n"; $t .= " -help | -silent | -test | -v\n"; $t .= "EXAMPLE:\n"; $t .= "Add .jpg to all non jpg files\n"; $t .= " renner . -unmask jpg\$ -app .jpg\n"; $t .= "\n"; $t = pagedump($t); $t .= "MATCH CRITERIA\n"; $t .= "\n"; $t .= " \$ - anchors a match to END of string\n"; $t .= " ^ - anchors a match to START of string\n"; $t .= "\n"; $t .= " -mask string\n"; $t .= " default: . \n"; $t .= "act only on filenames that match the string\n"; $t .= "ex: renner.pl . -mask .txt -app .bak\n"; $t .= "append .bak to any file in currect directory matching .txt\n"; $t .= " foo.txt -> foo.txt.bak\n"; $t .= " foo.txt.bak -> foo.txt.bak.txt\n"; $t .= "ex: renner.pl . -mask .txt\$ -app .bak\n"; $t .= "append .bak to any file with extension .txt\n"; $t .= " foo.txt -> foo.txt.bak\n"; $t .= " foo.txt.bak -> foo.txt.bak\n"; $t .= " -unmask string\n"; $t .= "act only on filenames that do NOT match the string\n"; $t .= "ex: renner.pl . -unmask ^_ -app .txt\n"; $t .= "append .txt to any file in current directory that does NOT\n"; $t .= "begin with underscore\n"; $t .= " _foo -> foo\n"; $t .= " foo -> foo.txt\n"; $t .= "NOTE: -mask and -umask may not be used in the same operation.\n"; $t .= "\n"; $t .= " -dir\n"; $t .= "Rename directories in addition to plain files.\n"; $t .= "NOTE: -dir and -r (recursion) may not be used in the same operation.\n"; $t = pagedump($t); $t .= "ADD OR REMOVE STRINGS FROM FILENAME\n"; $t .= " -app string\n"; $t .= " -pre string\n"; $t .= "append or prepend string to all matching filenames\n"; $t .= "ex: renner.pl . -app .bak\n"; $t .= "append .bak to all files in current directory\n"; $t .= " foo -> foo.bak\n"; $t .= "ex: renner.pl . -mask .gif\$ -pre _\n"; $t .= "prepend all .gif files in current directory with underscore\n"; $t .= " foo.gif -> _foo.gif\n"; $t .= " foo.txt -> foo.txt\n"; $t .= "\n"; $t .= " -unapp integer\n"; $t .= " -unpre integer\n"; $t .= "delete integer characters from start or end of filename.\n"; $t .= "ex: renner.pl . -mask .txt\$ -unapp 4\n"; $t .= "delete extension from all txt files in current directory\n"; $t .= " foo.txt -> foo\n"; $t .= "ex: renner.pl . -unmask . -unapp 1\n"; $t .= "delete leading character from all files in current directory with \n"; $t .= "no extension\n"; $t .= " afoo -> foo\n"; $t = pagedump($t); $t .= "PERFORM SUBSTITUIONS ON FILENAME\n"; $t .= " -mask searchstring - sub replacestring\n"; $t .= "replace searchstring in filename with replacestring. searchstring \n"; $t .= "is required in this form.\n"; $t .= "ex: renner.pl -mask display -sub d\n"; $t .= " display1.jpg -> d1.jpg\n"; $t .= "\n"; $t .= " -dig integer1 integer2\n"; $t .= "zeropad strings of integer1 consecutive digits to integer2 digits \n"; $t .= "ex: renner.pl -mask .txt\$ -dig 2 3\n"; $t .= " 23.txt -> 023.txt\n"; $t .= " 123.txt -> 123.txt\n"; $t .= "To include a space in a mask, sub, or unmask, use \$" . "space\n"; $t = pagedump($t); $t .= "RECURSION\n"; $t .= " -r\n"; $t .= "recursively traverse directories.\n"; $t .= "NOTE: -r and -dir (rename directories) may not be used in the same operation.\n"; $t .= "\n"; $t .= "UTILITY\n"; $t .= " -help\n"; $t .= "print this message\n"; $t .= "\n"; $t .= " -silent\n"; $t .= "suppress messages\n"; $t .= "\n"; $t .= " -test\n"; $t .= "describe action but don't actually rename files\n"; $t .= "\n"; $t .= " -v\n"; $t .= "print detailed messages\n"; print $t; exit; } sub pagedump { local ($string) = @_; print $string; print "\n...press Enter to continue...\n\n"; getc(); return ""; }