I\'m trying to lower-case all my extensions regardless of what it is. So far, from what I\'ve seen, you have to specify what file extensions you want to convert to lower-cas
So, these solutions that look like line noise are nice and all, but this is easy to do from the python REPL (I know the OP asked for bash, but python is installed on a lot of systems that have bash these days...):
import os
files = os.listdir('.')
for f in files:
path, ext = os.path.splitext(f)
if ext.isupper():
os.rename(f, path + ext.lower())
I was looking for a simple way to do this (without having to think about it) but I finally ended up thinking it through and came up with this (admittedly, way after the original post)
find . -name \\*.JPG -print -exec rename s/.JPG/.jpg/ {} \\;
I ran it on about 60 thousand files and it worked fine but, of course, you can use the -n
option to 'rename' if you want to test it out first.
This will do the job for your '.mp3's - but only in the working directory - however is able to consume filenames with whitespace:
for f in *.[mM][pP]3; do mv "$f" "${f%.*}.mp3"; done
Correction:
for f in *.[mM][pP]3; do [[ "$f" =~ \.mp3$ ]] || mv "$f" "${f%.*}.mp3"; done
If you have mmv
(=move multiple files) installed and your filenames contain at most one dot, you can use
mmv -v "*.*" "#1.#l2"
It does not get more than one dot right (since the matching algo for *
is not greedy in mmv
), however, it handles ()
and '
correctly. Example:
$ mmv -v "*.*" "#1.#l2"
FOO.BAR.MP3 -> FOO.bar.mp3 : done
foo bar 'baz' (CD 1).MP3 -> foo bar 'baz' (CD 1).mp3 : done
Not perfect, but much easier to use and remember than all the find/exec/sed
stuff.
This is shorter but more general, combined from other's answer:
rename 's/\.([^.]+)$/.\L$1/' *
Simulation
For simulation, use -n
, i.e. rename -n 's/\.([^.]+)$/.\L$1/' *
. This way you can see what will be changed before the real changes being performed. Example output:
Happy.Family.GATHERING.JPG renamed as Happy.Family.GATHERING.jpg
Hero_from_The_Land_Across_the_River.JPG renamed as Hero_from_The_Land_Across_the_River.jpg
rAnD0m.jPg1 renamed as rAnD0m.jpg1
Short explanation about the syntax
rename OPTIONS 's/WHAT_TO_FIND_IN_THE_NAME/THE_REPLACEMENT/' FILENAMES
\.([^.]+)$
means sequence of anything but dot ([^.]
) at the end of the string ($
), after dot (\.
).\L$1
means dot (\.
) followed by lowercase (\L
) of 1st group ($1
)[^.]+
)'
instead of double quote "
to wrap the regex to avoid shell expansionWell, you could use this snippet as the core of whatever alternative you need:
#!/bin/bash
# lowerext.sh
while read f; do
if [[ "$f" = *.* ]]; then
# Extract the basename
b="${f%.*}"
# Extract the extension
x="${f##*.}"
# Convert the extension to lower case
# Note: this only works in recent versions of Bash
l="${x,,}"
if [[ "$x" != "$l" ]]; then
mv "$f" "$b.$l"
fi
else
continue
fi
done
Afterwards, all you need to do is feed a list of the files you need to rename to its standard input. E.g. for all files under the current directory and any subdirectory:
find -type f | lowerext.sh
A small optimization:
find -type f -name '*.*' | lowerext.sh
You will have to be more specific if you need a more concrete answer than this...