OS X renaming using parameter expansion

 TAGS:undefinedWhen it comes to rename files via command line there is no rename utility under OS X without installing Homebrew. But I still never needed to install it since there is a lot you can do by just making use of the shell parameter expansion.

The parameter expansion allows you to manipulate variables in a very convenient way and when mixed with the mv command you have an unstoppable renaming tool. Let's see first what are variables and what is this parameter expansion:

$ var='PIC0001.JPG'
$ echo ${var}
PIC0001.JPG

In the example above you can see that we have assigned the value PIC0001.JPG to a variable named var and in the next line we have just printed its content. The same example with a little bit of magic:

$ echo ${var/PIC/2014_Holiday_}
2014_Holiday_0001.JPG

Here I substituted the ugly PIC preffix used by the photo camera and added the title of the album. We'll see the details on how this works later on.

Now if I wanted to rename all the pictures from the command line I would just iterate over all them:

for file in *.JPG; do echo mv "$file" "${file/PIC/2014_Holiday_}"; done

You can safely execute the previous command, no change will be made to this files because we added the echo to just show the command to be executed. Delete it to make changes effective.

Now that we have seen a simple example for remaning let's get deeper on what you can do with parameter expansion with some examples.

In order to do some safe testing I would recommend creating a new directory and inside put some random empty files:

for i in $(seq 1 100); do touch "$i-${RANDOM}-$i.txt"; done

That will create something like:

$ ls
1-21912-1.txt     2-16712-2.txt   3-22319-3.txt   ...

Now that you have the dummy files test and understand the following examples:

 Replacing patterns with strings

The format of this expansion is:

# Replace first match of the pattern only:
${variable/pattern/replace}

# Replace all matches of the pattern:
${variable//pattern/replace}

And now a batch example, replace all dashes in files by underscores:

for file in *.*; do echo mv "$file" "${file//-/_}"; done


mv 1-21912-1.txt 1_21912_1.txt
mv 10-848-10.txt 10_848_10.txt
mv 100-26921-100.txt 100_26921_100.txt
...

Important: Note that the double slash // will replace all matching appearances, but if you use just one slash then the replacement will stop after the first match. Try it.

Remove a pattern from the beginning

The format of this expansion is:

# Remove the pattern in the beginning:
${variable#pattern}

# Remove the pattern in the beginning (longest match possible):
${variable##pattern}

In action, remove the first part of the file:

$ for file in *.*; do echo mv "$file" "${file#*-}"; done

mv 1-21912-1.txt 21912-1.txt
mv 10-848-10.txt 848-10.txt
mv 100-26921-100.txt 26921-100.txt
...

See the difference when using ##:

$ for file in *.*; do echo mv "$file" "${file##*-}"; done
mv 1-21912-1.txt 1.txt
mv 10-848-10.txt 10.txt
mv 100-26921-100.txt 100.txt

The double hash ## is matching with the longest possibility and taking the last - in the file.

Remove a pattern at the end

The format of this expansion is:

# Remove the pattern at the end:
${variable%pattern}

# Remove the pattern at the end (longest match possible):
${variable%%pattern}

This works exactly like the previous expansion but matching the end. An example of removing the extension:

for file in *.*; do echo mv "$file" "${file%.txt}"; done

mv 1-21912-1.txt 1-21912-1
mv 10-848-10.txt 10-848-10
mv 100-26921-100.txt 100-26921-100
...

Replace only a substring

Just like any substring function in a variety of languages, the format is:

# Cut string from offset:
${variable%offset}
# Cut string from offset until length:
${variable%offset:length}

Remove 3 first characters:

for file in *.*; do echo mv "$file" "${file:3}"; done

mv 1-21912-1.txt 1912-1.txt
mv 10-848-10.txt 848-10.txt
mv 100-26921-100.txt -26921-100.txt

Take from the 3rd and then 5 characters:

for file in *.*; do echo mv "$file" "${file:3:5}"; done

mv 1-21912-1.txt 1912-
mv 10-848-10.txt 848-1
mv 100-26921-100.txt -2692

Want more?

http://www.gnu.org/software/bash/manual/html_node/Shell-Parameter-Expansion.html

Happy renaming!