How do I rename all files to lowercase?
Asked Answered
F

6

150

I have for example TREE.wav, ONE.WAV. I want to rename it to tree.wav, one.wav. How do I rename all files to lowercase?

Fig answered 16/10, 2011 at 20:18 Comment(4)
Are you comfortable with a Terminal/shell solution? Or do you want C/Objective-C code to accomplish that?Fredenburg
Terminal solution will be ok.Fig
I think this should be reopened. terminal code is code as wellVanquish
This should be a valid question on stackoverflow. This is also code.Encaenia
N
460

If you're comfortable with the terminal:

  1. Open Terminal.app, type cd and then drag and drop the Folder containing the files to be renamed into the window.
  2. To confirm you're in the correct directory, type ls and hit enter.
  3. Paste this code and hit enter:

    for f in *; do mv "$f" "$f.tmp"; mv "$f.tmp" "`echo $f | tr "[:upper:]" "[:lower:]"`"; done
    
  4. To confirm that all your files are lowercased, type ls and hit enter again.

(Thanks to @bavarious on twitter for a few fixes, and thanks to John Whitley below for making this safer on case-insensitive filesystems.)

Nonresistant answered 16/10, 2011 at 20:39 Comment(18)
Be careful. If you have files named foo.txt and FOO.TXT, this could clobber one of them.Mccall
The default filesystem in OS X is case-insensitive, but this could go bad. I just tried it and it moves the source file over the destination file. echo "Test 1" >> test1; echo "Test 2" >> test2; mv test1 test2; cat test2Nonresistant
With bash, you can just do: mv "$f" "${f,,}", or declare -l g=$f; mv "$f" "$g"Fontenot
i tried all these commands, i get "mv: ‘PPP.txt’ and ‘ppp.txt’ are the same file" and it doesnt lower case my file... any ideas? Is it because its in the same directory?Edison
After change the files to lowercase I wanted to replace spaces with underscores. I used this command for that: for f in *; do mv "$f" "echo $f | sed -e 's, ,_,g'"; done found on this page: chrislongcreativeservices.com/…Telegraphy
user2066039: This must must be a recent thing on the Mac, because most answers older than a year don't account for it. I accomplished the task by using an intermediate extension like 'jpg1'. So, JPG -> jpg1 -> jpg. Hope that helps.Rambutan
duplicate lowercase files: change mv to cpEtana
OS X users should rename each file to a temporary name first due to the case-insensitive filesystem, e.g.: for f in *; do mv "$f" "$f.tmp"; mv "$f.tmp" "`echo $f | tr "[:upper:]" "[:lower:]"`"; doneFungi
Any ideas how to also include the sub-folders in this. Works like a charm but all of my subs are still in caps. Thanks.Anthropology
this seems not working with directories where mv was interpreted as literately move instead of rename... Any ideas of how to deal with folders?Uremia
@DennySmith I believe changing the * to ** will make this recurse but I can't test it right now.Nonresistant
A quick tip for beginners is that you can actually drag the folder from Finder to terminal and it will automatically cd into what you dragged.Spitz
@JohnWhitley -- please post your comment as a separate answer -- it should be the accepted answer.Pasquale
@JohnWhitley, see my answer, am I missing something? I can't reproduce the issue you apparently were trying to defend against.Chloroplast
@AlexHarvey Has this always been the case? I seem to remember being able to create test and TEST in the same directory around the time this question was answered (7 years ago).Nonresistant
any idea, how would you make this recursive?Halloween
@AnujGakhar I tried changing the beginning from for f in * to for f in find . | grep '/';. This works in concept, but may rename subdirectories first which won't work on case-sensitive filesystems. Running the command N times will work for N-deep structures though.Nonresistant
To run it recursively: for f in */**; do mv "$f" "$f.tmp"; mv "$f.tmp" "`echo $f | tr "[:upper:]" "[:lower:]"`"; doneMonstrous
C
19

The question as-asked is general, and also important, so I wish to provide a more general answer:

Simplest case (safe most of the time, and on Mac OS X, but read on):

for i in * ; do j=$(tr '[:upper:]' '[:lower:]' <<< "$i") ; mv "$i" "$j" ; done

You need to also handle spaces in filenames (any OS):

IFS=$'\n' ; for i in * ; do j=$(tr '[:upper:]' '[:lower:]' <<< "$i") ; mv "$i" "$j" ; done

You need to safely handle filenames that differ only by case in a case-sensitive filesystem and not overwrite the target (e.g. Linux):

for i in * ; do j=$(tr '[:upper:]' '[:lower:]' <<< "$i") ; [ -e "$j" ] && continue ; mv "$i" "$j" ; done 

Note about Mac OS X:

Mac's filesystem is case-insensitive, case-preserving.

There is, however, no need to create temporary files, as suggested in the accepted answer and comments, because two filenames that differ only by case cannot exist in the first place, ref.

To show this:

$ mkdir test
$ cd test
$ touch X x
$ ls -l 
total 0
-rw-r--r--  1 alexharvey  wheel  0 26 Sep 20:20 X
$ mv X x
$ ls -l 
total 0
-rw-r--r--  1 alexharvey  wheel  0 26 Sep 20:20 x
Chloroplast answered 26/9, 2018 at 9:3 Comment(8)
Yes - but your example suggests that you can lowercase filenames using 'mv X x'. So it was only that I commented on.Interdigitate
mojave 10.14.5 : # touch X x # ls -la total 0 -rw-r--r-- 1 root root 0 Jun 24 15:19 X # mv X x mv: 'X' and 'x' are the same file # ls -la -rw-r--r-- 1 root root 0 Jun 24 15:19 XInterdigitate
Sorry for the crappy formatting. SO was not kind to me there.Interdigitate
And my bad - was in a ssh on my raspberry on a shared drive (hfsplus formatted) - there it doesn't work. But locally on my mac it does.Interdigitate
for i in * ; do j=$(tr '[:upper:]' '[:lower:]' <<< "$i") ; mv "$i" "$j" ; worked for me at catalina. Thanks.Asocial
This does nothing.Temikatemp
@Temikatemp What does nothingChloroplast
The commands above do nothing.Temikatemp
O
5

A fish shell version:

for old in *
    set new (echo $old | tr '[A-Z]' '[a-z]')
    mv $old $new
end
Orthoclase answered 23/3, 2020 at 9:31 Comment(0)
P
3

For those wanting to lowercase all files in the current directory and sub-directories:

# lower case all files in current dir & subdirs
for d in ./**/ ; do (cd "$d" &&  for x in ./*/ ; do (cd "$x" && for f in *; do mv "$f" "$f.tmp"; mv "$f.tmp" "`echo $f | tr "[:upper:]" "[:lower:]"`"; done); done); done

#list all directories
for f in ./**/ ; do echo $f; done

# lower case all files in a directory
for x in ./*/ ; do (cd "$x" && for f in *; do mv "$f" "$f.tmp"; mv "$f.tmp" "`echo $f | tr "[:upper:]" "[:lower:]"`"; done); done
Postwar answered 14/9, 2020 at 13:3 Comment(1)
I'm getting -bash: cd: ./*/: No such file or directoryHousewifery
D
0

A simple solution is by using tr command within a for loop.

for file in ./* ; do
    mv "$file" "$(tr '[:upper:]' '[:lower:]' <<<"$file")"
done

You can learn more about tr command here description of tr command

Doublespace answered 5/10, 2022 at 9:26 Comment(0)
A
0

i think this is the best solution.

for i in *; do mv "$i" "${i,,}"; done

easier, shorter, neater

Afroasian answered 22/12, 2022 at 13:51 Comment(1)
Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.Immix

© 2022 - 2024 — McMap. All rights reserved.