I come across a million postings about the best way to rename multiple files at once from the command line. Of course there are nearly as many solutions. Sure, it's possible (and sometimes desirable) to write a shell script using a combination of sed, awk, mv, and so on. But the solution I've found most useful and flexible for everyday file operations is a Perl script by Larry Wall and available at the CPAN repository
This utility is standard on most Linux installations, but if you want to use it in Mac OS X, you'll have to download the source, then build and install. The CPAN link will take you to a page where you can download the souce (currently at version 1.6) in tarball format (gnuzipped tar file). Extract the source code from the tarball:
$ tar xvzf rename-1.6.tar.gz
This will extract the directory source tree. Change to the working directory:
$ cd rename-1.6
Build the makefile
$ perl Makefile.PL
Build the executable
$ make
Install the executable & man files
$ sudo make install
This will install the perl executable 'rename'. You can locate it in your path with the "which" command:
$ which rename
For me it was installed into /usr/local/bin/rename.
For a brief guide on usage syntax, you can enter "man rename". However, the power of this perl script is that it utilizes the full range of perl regular expressions. So, for example, to capitilze every file in the current directory:
$ rename 's/(\w+[a-z])/\u\L$1/g' *
I realize this can be daunting for someone new to perl regular expression (regex), so let's break it down a bit. The first argument, everything between the single quotes, is the perl regular expression (regex) describing how you want to rename the files. The second (and any subsequent) argument is the list of files you want to rename. The file list can contain wildcards (as shown) which are expanded by the shell before executing the rename script.
Let's examine the regex with a basic example:
$ rename 's/old/new/' <files>
The initial "s" is the substitute command, followed by the text you want to search for followed by the text you want to replace it with. The search and replace strings are separated by the standard slash delimeter.
In the basic example above, rename will search for the first occurrence of string "old" and if it is found, replace it with the string "new". If you want rename to replace EVERY occurrence of the string, you need to pass the global tag at the end of the regex:
$ rename 's/old/new/g' <files>
Let's say you want to rename a list of image files:
IMG_3563.JPG IMG_3587.JPG IMG_3598.JPG
You want to change the "IMG_" prefix to "Paris_". Here is the command syntax:
$ rename 's/^IMG_/Paris_/' *.JPG
This introduces another special character, the caret (^) This specifier tells rename ONLY to match files where the IMG is at the beggining of the filename. While this isn't absolutely necessary, suppose you also had the following file:
London-IMG_2822.JPG
Without the "^" in the regex, the previous rename command would produce the following:
London-Paris_2822.JPG
Which may not be what you wanted. Specifying the caret in the regex would skip this file since the "IMG_" string does not appear at the beginning of the filename.
The inverse of "^" is "$", which restricts the search to the end of the filename. Note that in any *nix operating system (Unix/Linux/Mac OS X/etc), this includes any file "extension", since there is no distinction between name & extension.
$ rename 's/\.JPG$/.jpg/' *
The previous command will rename any files ending in ".JPG" to lower case ".jpg", and introduces another special regex character, the backslash (\). In actuality, we're introducing TWO special characters, since within the context of a regex, a period (or dot, ".") is also a special character. Let's start with the dot: In a regex, a dot is a wildcard which will match ANY single character. If you want to match a literal dot in the text string, you need to preface it with the backslash, which instructs the regex parser to interpret the next character as a literal character. You would use this for any characters which have special meanings in regex including things like quotes, brackets, parentheses, and others.
Regular expressions can be confusing at first, but their power is undeniable. If you're interested in further reading, you can search for help in perldocs or perlregex.
Comments
redundant
You can simply just do:
perl -pi -e 's/\.JPG/\.jpg/g' *.jpg
in your last example no need to waste disk space.