Rename Multiple Files with Linux

Written by
Date: 2007-12-30 10:36:30 00:00


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 known 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.
[^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 Linux distributions does not have it) 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

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