This question already has an answer here:

What is the command for renaming file extensions from uppercase to lowercase?





marked as duplicate by Gilles, GAD3R, thrig, DarkHeart, Archemar May 20 '17 at 6:20

This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.


If you know what file extensions you're dealing with, you can hard-code it:

for f in *.JPG
  mv "$f" "${f%.JPG}.jpg"

For the more-general case:

for f in *
  mv "$f" "${b}.${e,,}"

Where the heavy lifting is done with bash variable expansion to:

  • save off the extension (strip off as much as you can from the front of the filename until finding a period)
  • save off the rest of the filename (strip off a period to the end of the filename, minimally)
  • rename the file to the new filename, lower-case the extension (,,) in the process
rename ' -f and /[A-Z][^.]*$/ and s/\.[^.]+$/\L$&/' *

rename ' -f and s/\.[^.]*[A-Z][^.]*$/\L$&/' *

We need to realize that, under the hood, rename is just Perl code. Think of it as: the wildcard * feeds the names to this code in a loop and on each of these names we perform the following actions:

  • Test whether the current name (stored in loop container $_) is a regular file ( file-test operator -f filename, when filename is omitted, it defaults to $_ ) Note: To prevent rename from thinking that the -f we want for our file-test is an option to it we use a space before the -f to preclude that possibility!!!
  • It would be pointless to do a rename if a filename didn't have any uppercase character(s) to begin with. So we check for that fact in the extension of the filename via this regular expression: /[A-Z][^.]*$/ This looks at an unbroken run of non-dot characters seen from the filename's end to assert that at least one uppercase is present in the extension portion of the filename. It might so happen, that there's no extension to speak of. This fact is taken care of in the next step, where we look for a literal . in the filename as well.
  • Now we know that the current filename is a regular file AND it is a candidate for rename owing to the presence of at least one uppercase. The regex s/\.[^.]+$/\L$&/ isolates the complete extension portion in the current filename by looking from the filename's end and looking left and grabbing all non-dot [^.]+ characters till the time a literal \. is seen. The \L$& will turn all the uppercase -> lower in the matched text.
  • I've added a second version where we do all the work in one s/// command itself of checking an uppercase in extension.
  • Special Note: the m// and s/// normally run on an attached string via the =~ operator, as say, $var =~ m/[A-Z]+/ $filenm =~ s/ABC/DEF/. But in case the variable in question happens to be the $_ then we can dispense with the =~ and write it simply m/[A-Z]+/ s/ABC/DEF/ will imply the variable on which these regexes operate is the $_. Also, we can dispense with the m in case of m// when the delimiters are slashes. We however, do need it in case of say m{} m|| etc. This is a very common idiom in Perl style.
  • 1
    details about regexp crypticness would be welcomed. – Archemar May 19 '17 at 12:54

Just to add another answer which isn't yet listed:

for f in *.JPG; do mv "$f" "${f//JPG/jpg}"; done
  • Might have unintended consequences on filenames like "myJPG.JPG" – Jeff Schaller May 19 '17 at 14:33
  • @JeffSchaller you are right and I was aware of that indeed but than I'd be giving the same answer as yours :) – Valentin Bajrami May 19 '17 at 15:04
  • 1
    sure; and nothing against your answer, I just wanted to point out a potential pitfall. You could tweak it slightly with "${f//.JPG/.jpg}" – Jeff Schaller May 19 '17 at 15:26
  • Ah right, that's true and your answer is still the correct one. – Valentin Bajrami May 19 '17 at 17:46

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