find . -depth -name '*[A-Z]*'|sed -n 's/\(.*\/\)\(.*\)/mv -n -v -T \1\2 \1\L\2/p'|sh
I haven't tried the more elaborate scripts mentioned here, but none of the single commandline versions worked for me on my Synology NAS. rename
is not available, and many of the variations of find
fail because it seems to stick to the older name of the already renamed path (eg, if it finds ./FOO
followed by ./FOO/BAR
, renaming ./FOO
to ./foo
will still continue to list ./FOO/BAR
even though that path is no longer valid). Above command worked for me without any issues.
What follows is an explanation of each part of the command:
find . -depth -name '*[A-Z]*'
This will find any file from the current directory (change .
to whatever directory you want to process), using a depth-first search (eg., it will list ./foo/bar
before ./foo
), but only for files that contain an uppercase character. The -name
filter only applies to the base file name, not the full path. So this will list ./FOO/BAR
but not ./FOO/bar
. This is ok, as we don't want to rename ./FOO/bar
. We want to rename ./FOO
though, but that one is listed later on (this is why -depth
is important).
This comand in itself is particularly useful to finding the files that you want to rename in the first place. Use this after the complete rename command to search for files that still haven't been replaced because of file name collisions or errors.
sed -n 's/\(.*\/\)\(.*\)/mv -n -v -T \1\2 \1\L\2/p'
This part reads the files outputted by find
and formats them in a mv
command using a regular expression. The -n
option stops sed
from printing the input, and the p
command in the search-and-replace regex outputs the replaced text.
The regex itself consists of two captures: the part up until the last / (which is the directory of the file), and the filename itself. The directory is left intact, but the filename is transformed to lowercase. So, if find
outputs ./FOO/BAR
, it will become mv -n -v -T ./FOO/BAR ./FOO/bar
. The -n
option of mv
makes sure existing lowercase files are not overwritten. The -v
option makes mv
output every change that it makes (or doesn't make - if ./FOO/bar
already exists, it outputs something like ./FOO/BAR -> ./FOO/BAR
, noting that no change has been made). The -T
is very important here - it treats the target file as a directory. This will make sure that ./FOO/BAR
isn't moved into ./FOO/bar
if that directory happens to exist.
Use this together with find
to generate a list of commands that will be executed (handy to verify what will be done without actually doing it)
sh
This pretty self-explanatory. It routes all the generated mv
commands to the shell interpreter. You can replace it with bash
or any shell of your liking.