2008-03-24

Mass File Renaming in Unix or Linux

Here's a quick script that you can use to rename a bunch of files. It will rename all of the files in the working directory that have certain text to something else that you specify. For example, when you have a group of photos from a digital camera with sequentially numbered files like "IMG1.JPG, IMG2.JPG, IMG3.JPG...etc." that your would like to be called "2008-feb-baseball-1.jpg, 2008-feb-baseball-2.jpg, 2008-feb-baseball-3.jpg...etc.". The Code Create a text file called massren with this as the content:
#!/bin/sh for filename in *$1* do mv -fT "$filename" `echo $filename | sed -e "s/$1/$2/"` done
Then, make the file executable with:
chmod +x massren
Usage
masren textfrom textto Where: textfrom is the text to replace in each file name. textto is the new replacement text.
Example For example, to rename the files cited in the first paragraph:
./massren IMG 2008-feb-baseball- ./massren JPG jpeg
The first command replaces "IMG" in every file name to "2008-feb-baseball-". The second command replaces "JPG" in every file name to "jpeg". The reason I put "./" at the beginning pf each line is that on my system the working directory is not in the path. So, this addresses the script "massren" in the working directory explicitly...pretty normal in unix shells. Examining the Code
#!/bin/sh for filename in *$1* do mv -fT "$filename" `echo $filename | sed -e "s/$1/$2/"` done
This tells your unix shell where to file the program that executes this script. in this case, it is a Bach shell script and the program on my system is called "sh" and is in the "/bin/" directory. This line, in unix jargon is called the shebang line. This creates a variable called "filename" in a loop (from "do" to "done on the following lines) for each file in the working directory (the current directly) for each file that has the "textfrom" text that you specified. The "$1" in "*$1*" is a variable that contains the first parameter (like "IMG" in the example). The asterisks surrounding it mean that any file with this text somewhere in the file name will be selected. The "do" and "done" lines contain the loop. The code between them will be executed for every file matched on the green line. This line renames each file. In unix, "mv", the Move command is also used to rename files. The -fT parameters tell mv to go ahead and rename the file and that the file is being renamed and not being moved to another directory. You can see that we are using the $filename variable that was created on the green line - remember that this is a loop and will be run for every file that meets our criteria. "$filename" is enclosed in quotes in case the files being renamed has spaces in the name (in which case, the fromtext parameter would need to be quoted also. The next part is where the new file name is created using the "sed" command. Note that it is enclosed in "`" characters, called back ticks in unix jargon. Everything enclosed in back ticks is executed and the results of that execution is substituted in the brown command line. So, the current file name (in the $filename variable) is echoed through the sed command. "echo" gets the file name, the "|" (called a pipe in unix jargon) takes that text (the file name) and pipes it into the sed command. The sed command being used substitutes all of the fromtext (in the $1 variable) with the totext (in the $2 variable). Check out a reference for sed for details. You will see that the "s//" command does a simple substitution of one instance of text with another. Make your Own Command Take what you learn here and create your own mass file renaming script! Replace "*$1*" with a globing specification that selects the files you want to process. Replace the sed command I used here with, for example a tr command. You could use tr to rename file from UPPERCASE to lowercase: tr '[A-Z]' '[a-z]' You can easily debug your new script by inserting echo at the beginning of the brown line to just show the mv command line being created for each file instead of executing it. For example, for the new rename to lower case:
#!/bin/sh for filename in * do echo mv -fT "$filename" `echo $filename | tr '[A-Z]' '[a-z]'` done
Note that the selection criteria went from "*$1*" (select files that contain specified text) to "*" (all files in the working directory). Production Version
#!/bin/sh
#
# massren: Mass file rename utility
#
if [ $# -eq 2 ]
then
    for filename in *$1*
    do
          mv -fT "$filename" `echo $filename | sed -e "s/$1/$2/"`
    done
    exit 0
else
    echo "\nUsage:"
    echo "masren textfrom textto"
    echo "\nWhere:"
    echo "textfrom is the text to replace in each file name."
    echo "textto is the new replacement text.\n"
    exit 1
fi

1 comment:

Unknown said...

Mmmm thank you very much. I've been doing this a much more complicated way.

<3++