5

Suppose a folder with many files with bad extensions,for example

Song1.avi.mp3
Song2.avi.mp3
Song32.web.mp3
Song23.mp4.mp3
Song2a.mp9.mp3

I want to remove only the second field (web, avi, mp4). I know how to do with sed but I have to put the extension

 mv -v $i "$(echo $i|sed 's:.flv::g;s:.avi::g;s:.mp4::g')"

Does someone know an immediate method with sed or awk or perl to remove only the second bad extension?

elbarna
  • 12,695

4 Answers4

11

You don't need any external utility, you can do it with the shell's own string manipulation functionality. This makes it easier to avoid breaking on file names with special characters. And remember to always use double quotes around variable substitutions.

mv -v -- "$i" "${i%.*.*}.${i##*.}"

(Obviously this snippet assumes that the file name does contain two extensions. If it doesn't, ${i%.*.*} would be the whole file name.)

6

Using a bash regex:

f=foo.bar.baz.qux
if [[ $f =~ (.+)\.[^.]+\.([^.]+)$ ]];then
    new="${BASH_REMATCH[1]}.${BASH_REMATCH[2]}"
    if [[ -f "$new" ]]; then
        echo "moving $f would overwrite $new"
    else
        echo mv "$f" "$new"
    fi
fi
mv foo.bar.baz.qux foo.bar.qux

This has the advantage of doing nothing if there are less than 2 dots in the name.

glenn jackman
  • 85,964
5

If you need to validate a filename match - and so only rename those files which actually have the two extensions you're attempting to modify - you can just do:

case ${i##*/} in (*.*.*)
mv -- "$i" "${i%.*.*}.${i##*.}"
;;esac

Understand that if you do not validate the match and you're setting "$i" with a glob like:

for i in *
mv "$i" ...

...then using the same mv command as above (and in other answers) could result in the file being moved to "$i.$i" as the var expands to itself if the pattern does not match.

mikeserv
  • 58,310
4

Easy rename with mmv command:

$ mmv -n '*.*.*' '#1.#3'

or with rename command:

$ rename -n 's:(.*)\..*(\..*):$1$2:' *
αғsнιη
  • 41,407