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).
Alright, makes sense. What would you suggest if I want to rename a bunch of directories? Can this be done without errors without explicitly checking if they are the same? – Egon Olieux – 2016-03-19T05:13:05.467
I understand why moving to a different tree would work, but how is
./*
different from.
?./*
will expand to each item in the directory while.
will take the current directory, but in the end it's still moving within the same directory. Let's take the directorydir
for example, which contains 5 directoriesa
,b
,c
,d
ande.
If I want to rename all subdirectories ofdir
,find .
andfind ./*
will return the same result. – Egon Olieux – 2016-03-19T20:11:34.953Assuming the current working directory is
dir
. – Egon Olieux – 2016-03-19T20:19:16.320@FrankThomas +Egon:
-iname test
does not match.test
; it's clear from the second result (with echo) that it's really./test
and just misquoted.-ilname
is exactly the same as-iname
except for symbolic links which are not involved here../*
normally expands to all entries in.
EXCEPT those beginning with.
(dot), although some shells have an option to change this, inbash
shopt -s dotglob
. OTOHfind .
will always look at dotnames like./.profile
(other than.
and..
), although here any such name doesn't match the-iname
. – dave_thompson_085 – 2016-03-20T07:04:56.910