Super User is a question and answer site for computer enthusiasts and power users. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

I was looking for a way to rename a huge number of similarly-named files, much like this one (a Windows-related question) except that I'm using *nix (Ubuntu and FreeBSD, separately). Just to sum up, while using the shell (Bash, CSH, etc.) how do I mass-rename a number of files such that, for example, the following files:

Beethoven - Fur Elise.mp3
Beethoven - Moonlight Sonata.mp3
Beethoven - Ode to Joy.mp3
Beethoven - Rage Over the Lost Penny.mp3

will be renamed like these?

Fur Elise.mp3
Moonlight Sonata.mp3
Ode to Joy.mp3
Rage Over the Lost Penny.mp3

The reason I want to do this is that these collection of files will go under a directory named "Beethoven" (i.e. the filenames' prefix), and having this information on the filename itself will be redundant.

share|improve this question

The rename utility will do what you want.

Just use rename 's/Beethoven\ -\ //g' *.mp3

share|improve this answer
Can you please edit to provide a link to the utility, or is it standard in both distributions mentioned (Ubuntu and FreeBSD)? – Chris W. Rea Aug 21 '09 at 20:46
It comes with Perl. Debian uses it as the rename command, so I suspect Ubuntu does too. There is another 'rename' command that is worthless, so check the man page. – derobert Aug 23 '09 at 8:33
wow, the rename syntax looks very alike to vim replace :D – nXqd Jun 1 '11 at 3:25
the port in /usr/ports/sysutils/rename worked perfectly in FreeBSD – Josh W. Jan 9 '12 at 23:45

Like so many things with Linux/Unix, there is more than one way to do it!

Some might use mmv (mass mv).

The rename, or prename command that comes with some Perl packages (newer Ubuntu and Debian) can do this as well.

prename 's/Beethoven\ -\ //g' Beethoven*.mp3

Note that the rename tool on Fedora 10 is not the same program as this and works differently. It is part of a different package, util-linux-ng and can be found here.

I often just go to the shell for loop out of habit (after all such tools didn't always exist).

mkdir -p Beethoven
for x in Beethoven\ -\ *
mv "$x" Beethoven/"${x/Beethoven - /}"

This will create the Beethoven directory, then move the file to that directory/filename, where the filename has the "Beethoven - " replaced with nothing.

As a test, before:

$ ls
Beethoven - Fur Elise.mp3                 Beethoven - Ode to Joy.mp3
Beethoven - Moonlight Sonata.mp3          Beethoven - Rage Over the Lost Penny.mp3


$ ls Beethoven/
Fur Elise.mp3                 Ode to Joy.mp3
Moonlight Sonata.mp3          Rage Over the Lost Penny.mp3
share|improve this answer

Try this solution, implemented using a combination of grep and rename. This is assuming you have a whole bunch of directories that you need to rename. If there are just a few, I'd go with the manual approach, with the "Artist - " pattern hardcoded for each.

# Rename any mp3 files in the directory hierarchy of type "a - b.mp3" to "b.mp3"
find . -name "*.mp3" -exec rename -n -v 's|^(.*/).*-\s*(.*)\s*$|$1$2|g' {} \;

Explanation of find:
The find command finds all the files with .mp3 extension in the current file hierarchy, and calls the argument passed to -exec for each. Note that within -exec, {} refers to the argument passed by find (file path+name). The \; ensures the ; gets passed to rename and instead of indicating the end of the find command.

The command given above has the -n (no action) switch; hence it will only tell you what would happen if you ran it. I recommend you run this command without the -n switch only after you've run it once and are satisfied with the proposed results.

Now for the regexp.

  • ^ matches start of string.
  • $ matches the end of the string.
  • . matches any character.
  • * means zero or more of the preceeding construct. e.g .* means zero or more characters.
  • \s stands for any space character.
  • \S stands for any non-space character.
  • Anything within () gets captured and is reflected as $1, $2, depending on its position.

The regexp:

  • Looks for an optional directory structure at the start, captures this in $1: (.*/)
  • Skips everything till the "-" : .*-
  • Captures the rest of the string, excepting leading and trailing spaces, in $2: (.*)
  • Rewrites the file as $1$2, which should be "/path/to/file/""filename.mp3"

Here's my test run:

/tmp/test$ ls -R
a  b  c  z-unknown.mp3

a3.mp3                 a - longer title3.mp3  c.mp3   disc2
a - longer title2.mp3  a - long title.mp3     disc 1  the band - the title.mp3

./a/disc 1:
a - title1.mp3  a - title2.mp3

a - title1.mp3  a - title2.mp3

cd - ab - title3.mp3  cd - title1.mp3  cd - title2.mp3  c.mp3

c-pony2.mp4  c - pony3.mp3  c - pony4.mp3  c-pony.mp3

/tmp/test$ find . -name "*.mp3" -exec rename -v 's|^(.*/).*-\s*(.*)\s*$|$1$2|g' {} \;
./c/c-pony.mp3 renamed as ./c/pony.mp3
./c/c - pony4.mp3 renamed as ./c/pony4.mp3
./c/c - pony3.mp3 renamed as ./c/pony3.mp3
./z-unknown.mp3 renamed as ./unknown.mp3
./a/the band - the title.mp3 renamed as ./a/the title.mp3
./a/a - longer title2.mp3 renamed as ./a/longer title2.mp3
./a/a - longer title3.mp3 renamed as ./a/longer title3.mp3
./a/disc 1/a - title1.mp3 renamed as ./a/disc 1/title1.mp3
./a/disc 1/a - title2.mp3 renamed as ./a/disc 1/title2.mp3
./a/a - long title.mp3 renamed as ./a/long title.mp3
./a/disc2/a - title1.mp3 renamed as ./a/disc2/title1.mp3
./a/disc2/a - title2.mp3 renamed as ./a/disc2/title2.mp3
./b/cd - title1.mp3 renamed as ./b/title1.mp3
./b/cd - title2.mp3 renamed as ./b/title2.mp3
./b/cd - ab - title3.mp3 renamed as ./b/title3.mp3

/tmp/test$ ls -R
a  b  c  unknown.mp3

a3.mp3  c.mp3  disc 1  disc2  longer title2.mp3  longer title3.mp3  long title.mp3  the title.mp3

./a/disc 1:
title1.mp3  title2.mp3

title1.mp3  title2.mp3

c.mp3  title1.mp3  title2.mp3  title3.mp3

c-pony2.mp4  pony3.mp3  pony4.mp3  pony.mp3

Regexp's are tricky business, and I've made many a blunder writing them, so I'd welcome any input on the lack of merit of this one. I know I found quite a few testing this.

share|improve this answer

I've put together a command-line Java program that makes renaming files (and directories) a breeze, especially for scripting. It's free and open source, so you can modify it to your heart's content:


Some relevant usage examples:

Move files of the form "<a> - <b>" to their respective directory "<a>":

java -jar RenameWand.jar  "<a> - <b>"  "<a>/<b>"

Sort files by last-modified time, and rename them with a 3-digit number:

java -jar RenameWand.jar  "<a>"  "<3|#FT> <a>"

Rearrange parts of the filename, and change case:

java -jar RenameWand.jar  "<album> - <artist> - <song>.<ext>" 
                          "<artist.upper> <album.title> - <song>.<ext.lower>"
share|improve this answer

For Penguin heads this is easily done in a shell script or AWK script. For us mere mortals you might want to try Midnight Commander. It's on most linux distributions, from a shell prompt type mc -a. You can rename files using regular expressions. I used the article at GeekStuff to help me.

share|improve this answer

zmv The zsh renaming tool is very good.

# zmv "programmable rename"
# Replace spaces in filenames with a underline
zmv '* *' '$f:gs/ /_'
# Change the suffix from *.sh to *.pl
zmv -W '*.sh' '*.pl'
# lowercase/uppercase all files/directories
$ zmv '(*)' '${(L)1}' # lowercase
$ zmv '(*)' '${(U)1}' # uppercase

More notes here...

share|improve this answer

Here is a simple command-line example. I had the word "white" in the middle of the names of a bunch of png files. I wanted to take it out and leave just a single underscore. This did the trick:

for i in *.png; do mv "$i" "${i/white/}"; done
share|improve this answer

Use vidir and then use your editor features to apply the renaming pattern.


vidir - edit directory


vidir [--verbose] [directory|file|-] ...


vidir allows editing of the contents of a directory in a text editor. If no directory is specified, the current directory is edited.

When editing a directory, each item in the directory will appear on its own numbered line. These numbers are how vidir keeps track of what items are changed. Delete lines to remove files from the directory, or edit filenames to rename files. You can also switch pairs of numbers to swap filenames.

Note that if "-" is specified as the directory to edit, it reads a list of filenames from stdin and displays those for editing. Alternatively, a list of files can be specified on the command line.


vidir vidir *.jpeg Typical uses.

find | vidir - Edit subdirectory contents too. To delete subdirectories, delete all their contents and the subdirectory itself in the editor.

find -type f | vidir - Edit all files under the current directory and subdirectories.


Joey Hess 2006-2010

Modifications by Magnus Woldrich 2011


Copyright 2006-2011 the vidir "AUTHOR"s as listed above.

Licensed under the GNU GPL.

share|improve this answer

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .