I am new to scripting, and I have a directory with all files named num.pdb.ostat. I would like to rename all num.ostat (that is deleting the .pdb in all). For a single file this works:

mv 2.pdb.ostat 2.ostat

but when I try to do it for all files in folder with this script

for num in ./*; do mv ${num}.pdb.ostat ${num}.ostat; done

nothing happens

Can anyone tell me, where I went wrong?

  • 1
    No. But ever seen the rename.ul utility? It will be something like this: rename.ul pdb. . *ostat and it should rename the files. – Rinzwind Mar 9 '15 at 9:17
  • Or (assuming you are using perl rename) rename 's/pdb.//' *.pdb.ostat – Sparhawk Mar 9 '15 at 9:19
  • Does that mean, I can bypass the loop and just use the rename.ul when I am in the directory? It gives me this response : -bash: syntax error near unexpected token `pdb.' – Ditte Mar 9 '15 at 9:20
  • @akabhirav The question is Can anyone tell me, where I went wrong?, so it's not a dupe exactly, although the link is certainly helpful. – Sparhawk Mar 9 '15 at 9:29

${num} takes the whole file name. You need to get filename without extension and add your new extension. You can make a string formatting. Use the following command:

for num in ./*; do mv ${num} ${num%.*.*}.ostat ; done

% deletes shortest match of $substring from back of $string.

  • 1
    Thank you. This was so simple that I could understand it, and it worked nicely :) – Ditte Mar 9 '15 at 10:54
  • 2
    +1 I always forget about parameter substitution. This won't work for files with spaces in them, but is fine for this question. Also, you could use the greedy expression ${num%%.*}.ostat instead, and save one character! :) – Sparhawk Mar 11 '15 at 1:42

For troubleshooting your script, try replacing mv with echo. You'll see that your variable ${num} contains the full file name, e.g. 2.pdb.ostat. Hence your script essentially tries to run

mv ./2.pdb.ostat.pdb.ostat ./2.pdb.ostat.ostat

Instead, you have to truncate the filename back to just the number first. e.g.

for filename in ./*; do num="$(echo "${filename}" | grep -o '^./[0-9]*')"; echo "${num}.pdb.ostat" "${num}.ostat"; done

Once you have confirmed the syntax is okay, you can change the echo to a mv, and actually move the files. i.e.

for filename in ./*; do num="$(echo "${filename}" | grep -o '^./[0-9]*')"; mv "${num}.pdb.ostat" "${num}.ostat"; done

Nevertheless, the easiest way is to use (perl) rename.

rename 's/pdb.//' *.pdb.ostat –

See man rename for more info.


Here's a bash script that accomplishes what you want in a less specific way.


# a bash script for changing the extension of files.
echo "what extension would you like to change in this directory?"
read oldext
echo "To what?"
read newext
for f in *.* 
    name=$(echo "$f" | sed 's/\.[^\.]*$//')
    ext=$(echo "$f" | sed 's/^.*\.//')
    echo "source file" "$f" is made up of the base "$name" and ends with "$ext"
    if [ -e "$target" ];
        echo "$target" exists. skipping renameing.
        mv "$f" "$target"
        echo changed "$f" to "$target"


This script does not break on filenames with spaces and allows you to choose the source and target extensions.

It provides examples of a for loop, reading input into variables, using sed to pick a string apart at the last . in the string (filename), how spaces can be handled properly by quoting variables, checking for the existence of a target file and flow control based on the result of a test. It does spam the terminal with unnecessary output that can be eliminated by simple deleting lines 14 and 20 which are really only there to serve as explanation.


Here a script building on prior response. Find all files in the directory with name containing 'Igua' then rename all files including the right extension

for file in *Igua*
  let "i++"
  mv "$file" "Iguazu_$i.$fileext"

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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