Ask Ubuntu is a question and answer site for Ubuntu users and developers. It's 100% free.

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 have several folders of video files that need to be renamed to something uniform, eg: foldername.videotypexvideonumber.avi. I have looked at creating a shell script to make this easier. The mv command seems to be the best way to do this.

However, every guide/tutorial/manpage I've seen says that when I rename a file I have to also include the file extension. This would normally be fine, but some folders have videos of multiple file types, eg .mkv and .avi and even some .rmvb files.

So, what I need to know is if there's a way to rename files through the terminal without having to specify the file type when doing so - basically so that the extension stays the same, regardless of what it is before renaming.

share|improve this question
up vote 1 down vote accepted

Quick answer:

You can't do that since extensions are part of filename.

Long answer:

You can use a graphical interface to do advanced renames as purrr or gprename


In your batch renaming script you can use the following techniques of filename splitting:

DIRNAME=$(dirname ${FULLFILENAME})   #-- /home/user/video
BASENAME=$(basename ${FULLFILENAME}) #-- myvideo-release.xvid.128kbps.avi
FILENAME=${BASENAME%.*}              #-- myvideo-release.xvid.128kbps
EXTENSION=${BASENAME##*.}            #-- avi
share|improve this answer
I don't really understand what is said at the beginning. Obviously, anything you can do in a script you can do in a shell... – frabjous Jan 22 '11 at 15:21
Nice one, thanks a lot. That should make my life easier. – Saladin Akara Jan 22 '11 at 15:28
Also, you probably want things like FILENAME="${BASENAME%.*}" with the quotes in case the filenames have spaces in them. – frabjous Jan 22 '11 at 15:29
I have edited a bit to clarify the point. – ulidtko Jan 22 '11 at 15:30
Why are you using basename and dirname when you already know how to use parameter expansion? Also, you failed to quote the arguments to basename and dirname, so if someone tries your solution, they'll get problems with filenames containing special characters. And lastly, the convention is to use lower case variable names for everything but environment variables. Please see – geirha Feb 2 '11 at 8:54

It would help to know exactly what you want to do, but you can certainly do this. Learning about BASH parameter expansion is probably pretty necessary.

Depending on what you what to do, you may need to separate the extension and the filename, or maybe not.

I'm going to suppose you've already cded into the folder with the files in question.

case 1: suppose you want to change the string "bad" to "good" in every file name; then you can use a simple substitution, i.e., you can do something like:

for file in * ; do mv "$file" "${file//bad/good}" ; done

(Do make sure that there is no change that changing bad to good will overwrite something already there.) That'll work regardless of extension.

case 2: Suppse you need to add "new" before the extension, whatever it is, then you can do:

for file in * ; do filename="${file%.*}" ; extension="${file##*.}" ; mv "$file" "${filename}new.${extension}" ; done

The extension will remain the same, whatever it was.

I'd give more advice, but again, I really don't know what you're trying to do, exactly.

share|improve this answer
In terms of exactly what I want to do: I want to batch rename files from (for example) [DB]_2437968_Bleach_298.avi to Bleach.09x12.avi - that would be no problem if every file had the same extension. I want to change the file name only before the extension. – Saladin Akara Jan 22 '11 at 16:20
Where does the 09x12 come from, and how do you determine what part of the old filename to use, e.g. how would you know to use Bleach in this case? – geirha Jan 22 '11 at 17:29
Indeed; you can certainly do this, but we need to know the exact rules for how to transform the name. – frabjous Jan 22 '11 at 18:03
[temp] λ = ls
test.doc  test.rtf  test.txt
[temp] λ = for f in *; do mv "$f" test2`echo "$f" | sed 's/[^.]*//'`; done
[temp] λ = ls
test2.doc  test2.rtf  test2.txt

There might be a more elegant way to do it but it works

Replace test2 with anything you want a counter or something.

share|improve this answer

Your Answer


By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.