Say you want to rename all files in directory and all of its subdirectories in a systematic way. As an example, we construct a command that renames all files whose name contains the substrings "song" and "abc2009" with a name where the "abc2009" has been replaced with "def2010".
For example, a file name "song47abc2009.jpg" would be renamed to "song47def2010.jpg". The following command combo would accomplish that:
This looks a little messy, but it is worth while understanding how it works since this approach can be used for other complex operations. So let's break this down and review what each part is doing.
find . -name '*song*abc2009*.jpg' | sed 's/\(^.*song.*\)abc2009\(.*.jpg\)$/mv "&" "\1def2010\2"/' | sh
The three commands are separated by the "pipe" symbol "|", which passes the output of the previous command to the next command as input.
The find command takes as input a directory, in this case the current directory denoted as ".", and the "-name" flag, which specifies that the next parameter, in this case "*song*abc2009*.txt", serves as filter for the list of files returned by "find" command. So find, in this case, returns all file names under the current directory that match the pattern "*song*abc2009*.jpg", where the wildcard character "*" can match anything.
The list of file names is then passed on to the command sed, which stands for "stream editor". This command applies an editor command to each file name received in the input stream. In this case the edit command substitutes each filename with a "mv" command, that renames the filename as specified.
The substitution command is of the form "s/string1/string2", which specifies that string1 should be replaced with string2. In this case string1 is the regular expression "\(^.*song.*\)abc2009\(.*.jpg\)$", which is interpreted as follows. Ignoring the "\(" and "\)" for the moment, the "^" matches the start of the filename, which is followed by ".*", which means any number of characters (the "." matches any character, and the "*" means zero or more of them). This is followed by "song", which is followed by ".*" (any number of any characters), by "abc2009", by ".*" again, and by ".jpg".
The "\(" and "\)" codes are used to capture in the containing portions of the string in special variables, so that they can be used to construct the new file name.
So if we apply the regular expression to "song47abc2009.jpg", the first pair of "\(" and "\)" would capture "song47" in the first variable and the second pair of "\(" and "\)" would capture ".jpg" in the second variable. These two variables are accessed with "\1" and "\2" when constructing the replacement string.
The replacement string is specified by "mv "&" "\1def2010\2"". The "&" inserts the string that is being replaced (string1), and "\1" and "\2" insert the parts of the string as mentioned above. So in our example the replacement string being constructed would be:
which is the Linux rename command for changing the filename as specified.
mv song47abc2009.jpg song47def2010.jpg
This command is then executed by piping it to the sh command (a "shell").
The same procedure is performed on all the filenames produced by the initial find command.
Now that you understand the details of this sequence of commands and how they are linked, you can use similar methods to compose other complex large scale operations.