If the name is already in lower case, it will be given to the mv command twice, as you've seen.
If the last argument to mv is a directory, it will be treated as the destination dir into which all the other named entities should be moved.
mv test test
will first check the last argument, whether it exists and, if so, if it's a directory. In this case it is, so mv will check whether it's the same mount point (if it isn't, i.e. the destination is a different device, it will need to copy the file then remove the original); in this case, it is. So mv constructs a sequence of rename(2)
syscalls, appending all source names in turn to the directory specified as the destination: mv a b c d/
would generate rename("a", "d/a")
, rename("b", "d/b")
, and rename("c", "d/c")
- so of course mv test test
will try to call rename("test", "test/test");
. Which is obviously an error, you can't move a directory inside itself.
To fix your problem, make the mv command conditional on the new name being different and not already existing (if you have two different files called "Test" and "test", you probably don't want to replace the second without asking). Without me having tested this, and typing it on a phone, it'll look something like this: new="$(echo "$old" | tr ...)"; [[ $new != $old && ! -e $new ]] && mv "$old" "$new"
(watch the quotes, you don't want spaces in names to give you metaphorical wedgies).