Rename files using regular expression in linux

I have a set of files named like:

Friends - 6x03 - Tow Ross' Denial.srt
Friends - 6x20 - Tow Mac and C.H.E.E.S.E..srt
Friends - 6x05 - Tow Joey's Porshe.srt

and I want to rename them like the following

S06E03.srt
S06E20.srt
S06E05.srt

what should I do to make the job done in linux terminal? I have installed rename but U get errors using the following:

rename -n 's/(\w+) - (\d{1})x(\d{2})*$/S0$2E$3\.srt/' *.srt

You forgot a dot in front of the asterisk:

rename -n 's/(\w+) - (\d{1})x(\d{2}).*$/S0$2E$3\.srt/' *.srt

On OpenSUSE, RedHat, Gentoo you have to use Perl version of rename. This answer shows how to obtain it. On Arch, the package is called perl-rename.


Really cool lil diddy. find + perl + xargs + mv

xargs -n2 makes it possible to print two arguments per line. When combined with Perl's print $_ (to print the $STDIN first), it makes for a powerful renaming tool.

find . -type f | perl -pe 'print $_; s/input/output/' | xargs -d "\n" -n2 mv

Results of perl -pe 'print $_; s/OldName/NewName/' | xargs -n2 end up being:

OldName.ext    NewName.ext
OldName.ext    NewName.ext
OldName.ext    NewName.ext
OldName.ext    NewName.ext

I did not have Perl's rename readily available on my system.


How does it work?

  1. find . -type f outputs file paths (or file names...you control what gets processed by regex here!)
  2. -p prints file paths that were processed by regex, -e executes inline script
  3. print $_ prints the original file name first (independent of -p)
  4. -d "\n" cuts the input by newline, instead of default space character
  5. -n2 prints two elements per line
  6. mv gets the input of the previous line

Edit: found a better way to list the files without using IFS and ls while still being sh compliant.

I would do a shell script for that:

#!/bin/sh
for file in *.srt; do
  if [ -e "$file" ]; then
    newname=`echo "$file" | sed 's/^.*\([0-9]\+\)x\([0-9]\+\).*$/S0\1E\2.srt/'`
    mv "$file" "$newname"
  fi
done

Previous script:

#!/bin/sh
IFS='
'
for file in `ls -1 *.srt`; do
  newname=`echo "$file" | sed 's/^.*\([0-9]\+\)x\([0-9]\+\).*$/S0\1E\2.srt/'`
  mv "$file" "$newname"
done

Not every distro ships a rename utility that supports regexes as used in the examples above - RedHat, Gentoo and their derivatives amongst others.

Alternatives to try to use are perl-rename and mmv.


Use mmv (mass-move?)

It's simple but useful: The * wildcard matches any string (without slashes) and ? matches any character in the string to be matched. Use #X in the replace string to refer to the X-th wildcard match.

In your case:

mmv 'Friends - 6x?? - Tow *.srt' 'S06E#1#2.srt'

Here #1#2 represent the two digits which are captured by ?? (match #1 and #2).
So the following replacement is made:

Friends - 6x?? - Tow *           .srt    matches
Friends - 6x03 - Tow Ross' Denial.srt    which is replaced by
            ↓↓
        S06E03.srt

mmv also offers matching by [ and ] and ;.

You can not only mass rename, but also mass move, copy, append and link files.

See the man page for more!

Personally, I use it to pad numbers such that numbered files appear in the desired order when sorted lexicographically (e.g., 1 appears before 10): file_?.extfile_0#1.ext