4

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?

4
  • 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, 2015 at 9:17
  • Or (assuming you are using perl rename) rename 's/pdb.//' *.pdb.ostat
    – Sparhawk
    Mar 9, 2015 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, 2015 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, 2015 at 9:29

4 Answers 4

6

${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.

2
  • 1
    Thank you. This was so simple that I could understand it, and it worked nicely :)
    – Ditte
    Mar 9, 2015 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, 2015 at 1:42
5

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.

2

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

#!/bin/bash

#renext.sh
# 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 *.* 
do
    name=$(echo "$f" | sed 's/\.[^\.]*$//')
    ext=$(echo "$f" | sed 's/^.*\.//')
    target="$name"."$newext"
    echo "source file" "$f" is made up of the base "$name" and ends with "$ext"
    if [ -e "$target" ];
    then 
        echo "$target" exists. skipping renameing.
    else
        mv "$f" "$target"
        echo changed "$f" to "$target"
    fi  

 done

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.

0

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

#!/bin/bash
for file in *Igua*
do
  let "i++"
  fileext=${file##*.}
  mv "$file" "Iguazu_$i.$fileext"
done

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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