for f in *.old_ext; do
mv -- "$f" "$(echo "$f" | sed "s/\.old_ext$/.new_ext/")"
done
I am posting this because I have not seen another answer that details this method and why it could potentially be superior to the accepted answer. You can go here to see all the reasons why this method is better than all the other answers, but basically, the accepted answer is not POSIX-compliant since it relies on bash
parameter expansion.
I realize OP tagged bash
specifically, and for that reason, the accepted answer will work just fine, but if you wanted to use this command in a shell script on a system using sh
or dash
, you could use the version I posted above, which utilizes any version of sed
(GNU/BSD/anything), and will work just fine, while not relying specifically on bash
itself.
I actually wrote that command for this specific use case, which I encounter frequently and have been using it as a bash
/zsh
function for a long time, which I named chext
:
chext() {
old_ext="$1"
new_ext="$2"
for file in *.${old_ext}; do
mv -v -- "$file" "$(echo "$file" | sed "s/\.${old_ext}$/.${new_ext}/")"
done
}
Usage:
chext [old_extension] [new_extension]
Recently, I had the need to use it on a different computer, and instead of just a one-off copy/paste, I actually added it to my main set of portable commands, phxutils.
After publishing chext
in phxutils
, I did a quick search to see if there was actually a better way of accomplishing what I set out to do, and after browsing through all of these answers, I still think my way is the best and most universal (at least for current directory extension replacement -- for other methods, I would use one of the find
variations)
find . -iname '*.txt' -exec bash -c 'mv -- "$1" "${1%.txt}.text"' bash {} \;
mv $x "`basename $x .txt`.text"
.