Console logo</img>

Different ways to rename bulk files in Linux, using mv and rename

We are going to explore different ways to change names of multiple files using command line of Linux Operating System.

We are going to use rename which is a perl script, and also the know mv, together with for, in “one-line” shell script

rename

Syntax

rename [ -v ] [ -n ] [ -f ] perlexpr [ files ]

-v
Verbose: print names of files successfully renamed.
-n
No Action: show what files would have been renamed.
-f
Force: overwrite existing files.
perlexpr
Perl Expression

Regular Expressions

^
matches the beginning of the line
$
matches the end of the line
.
Matches any single character
(character)*
match arbitrarily many occurences of (character)
(character)?
Match 0 or 1 instance of (character)
[abcdef]
Match any character enclosed in [] (in this instance, a b c d e or f) ranges of characters such as [a-z] are permitted. The behaviour of this deserves more description. See the page on grep for more details about the syntax of lists.
[^abcdef]
Match any character NOT enclosed in [] (in this instance, any character other than a b c d e or f)
(character)\{m,n\}
Match m-n repetitions of (character)
(character)\{m,\}
Match m or more repetitions of (character)
(character)\{,n\}
Match n or less (possibly 0) repetitions of (character)
(character)\{n\}
Match exactly n repetitions of (character)
\(expression\)
Group operator.
\n
Backreference - matches nth group
expression1\|expression2
Matches expression1 or expression 2. Works with GNU sed, but this feature might not work with other forms of sed.
\w
matches any single character classified as a “word” character (alphanumeric or “_”)
\W
matches any non-“word” character
\s
matches any whitespace character (space, tab, newline)
\S
matches any non-whitespace character
\d
matches any digit character, equiv. to [0-9]
\D
matches any non-digit character
As rename is a perl script you will need perl to run it, and here are some examples about how to use it.

$ rename -v 's/\.htm$/\.html/' *.htm

This is going to change htm to html in every file ending with .htm in its name. If you want to change the name of something like this:
-rw-r--r-- 1 ggarron ggarron 0 2007-12-30 19:33 1.txt
-rw-r--r-- 1 ggarron ggarron 0 2007-12-30 19:33 2.txt
-rw-r--r-- 1 ggarron ggarron 0 2007-12-30 19:34 3.txt
-rw-r--r-- 1 ggarron ggarron 0 2007-12-28 20:35 b.txt
-rw-r--r-- 1 ggarron ggarron 0 2007-12-28 20:35 c.txt
-rw-r--r-- 1 ggarron ggarron 0 2007-12-28 20:35 d.txt
-rw-r--r-- 1 ggarron ggarron 0 2007-12-28 20:35 e.txt
That is the output of ls -l, and are files created with touch by me for this examples. Now lets say I want to add a more descriptive string to the name of these files like Thesis, so here we go.

rename -n 's/(\w{1})\.txt$/$1_thesis\.txt/' *.txt

Note: I am using -n to make only a test and see if the result is what I want
1.txt renamed as 1_thesis.txt
2.txt renamed as 2_thesis.txt
3.txt renamed as 3_thesis.txt
b.txt renamed as b_thesis.txt
c.txt renamed as c_thesis.txt
d.txt renamed as d_thesis.txt
e.txt renamed as e_thesis.txt
As you see that is what I wanted, now lets suppose I only want to change the name to files with a number in the name and with a letter in it.

rename -n 's/(\d{1})\.txt$/$1_thesis\.txt/' *.txt

1.txt renamed as 1_thesis.txt
2.txt renamed as 2_thesis.txt
3.txt renamed as 3_thesis.txt
You can also match only the ones with non-digit names

rename -n 's/(\D{1})\.txt$/$1_thesis\.txt/' *.txt

And the output will be:
b.txt renamed as b_thesis.txt
c.txt renamed as c_thesis.txt
d.txt renamed as d_thesis.txt
e.txt renamed as e_thesis.txt
As you may see, it is just a "using the right regexp" thing. In case you do not have rename on your system (I think non-Debian does not have) you can use mv

Using mv

Introduction Here we will first need to learn something about bash string operators Match and substitute, there are two basic forms for this, substitute from the right of the match and from the left of the match. substitution from the right ${var%t*string} Now if we want to erase the word thesis from the previous example just enter:

for i in *.txt; do mv "$i" "${i%t*.txt}.txt"; done

Before:
-rw-r--r-- 1 ggarron ggarron    0 2007-12-30 20:24 1_thesis.txt
-rw-r--r-- 1 ggarron ggarron    0 2007-12-30 20:24 2_thesis.txt
-rw-r--r-- 1 ggarron ggarron    0 2007-12-30 20:24 3_thesis.txt
-rw-r--r-- 1 ggarron ggarron    0 2007-12-30 20:24 b_thesis.txt
-rw-r--r-- 1 ggarron ggarron    0 2007-12-30 20:24 c_thesis.txt
-rw-r--r-- 1 ggarron ggarron    0 2007-12-30 20:24 d_thesis.txt
-rw-r--r-- 1 ggarron ggarron    0 2007-12-30 20:24 e_thesis.txt
After:
-rw-r--r-- 1 ggarron ggarron    0 2007-12-30 20:24 1_.txt
-rw-r--r-- 1 ggarron ggarron    0 2007-12-30 20:24 2_.txt
-rw-r--r-- 1 ggarron ggarron    0 2007-12-30 20:24 3_.txt
-rw-r--r-- 1 ggarron ggarron    0 2007-12-30 20:24 b_.txt
-rw-r--r-- 1 ggarron ggarron    0 2007-12-30 20:24 c_.txt
-rw-r--r-- 1 ggarron ggarron    0 2007-12-30 20:24 d_.txt
-rw-r--r-- 1 ggarron ggarron    0 2007-12-30 20:24 e_.txt
substitution from the left ${var#string} And if we want to replace .txt for .txt.bak just enter: Now lets suppose we have this:
-rw-r--r-- 1 ggarron ggarron    0 2007-12-30 20:28 thesis-1_.txt
-rw-r--r-- 1 ggarron ggarron    0 2007-12-30 20:28 thesis-2_.txt
-rw-r--r-- 1 ggarron ggarron    0 2007-12-30 20:28 thesis-3_.txt
-rw-r--r-- 1 ggarron ggarron    0 2007-12-30 20:28 thesis-b_.txt
-rw-r--r-- 1 ggarron ggarron    0 2007-12-30 20:28 thesis-c_.txt
-rw-r--r-- 1 ggarron ggarron    0 2007-12-30 20:28 thesis-e_.txt
And we want to erase the word thesis Just enter this:

for f in thesis*; do mv "$f" "${f#thesis-}"; done

And the output of ls -l will now be:
-rw-r--r-- 1 ggarron ggarron    0 2007-12-30 20:28 1_.txt
-rw-r--r-- 1 ggarron ggarron    0 2007-12-30 20:28 2_.txt
-rw-r--r-- 1 ggarron ggarron    0 2007-12-30 20:28 3_.txt
-rw-r--r-- 1 ggarron ggarron    0 2007-12-30 20:28 b_.txt
-rw-r--r-- 1 ggarron ggarron    0 2007-12-30 20:28 c_.txt
-rw-r--r-- 1 ggarron ggarron    0 2007-12-30 20:28 e_.txt