当尝试将某些文件转换为小写时,我注意到一些对我来说很奇怪的事情。
在 bash 中执行此操作时:
find . -iname 'test' | while IFS='\n' read item; do mv $item $(echo $item | tr [:upper:] [:lower:]); done
并且 mv 的源和目标没有改变,我收到以下错误:
mv: cannot move '.test' to a subdirectory of itself, './test/test'
这个是./test/test
从哪里来的?当回显而不是执行 mv 时,我得到的是mv ./test ./test
。我在 FreeBSD 10 和 Debian 8.2.0 上都测试了这一点,结果相同。我遗漏了什么?
答案1
如果名称已经是小写,则会将其提供给 mv 命令两次,正如您所见。
如果 mv 的最后一个参数是一个目录,它将被视为所有其他命名实体应移动到的目标目录。
mv test test
首先会检查最后一个参数是否存在,如果存在,则检查它是否为目录。在本例中是的,因此 mv 会检查它是否是同一个挂载点(如果不是,即目标是不同的设备,则需要复制文件然后删除原始文件);在本例中是的。因此 mv 构造了一个系统调用序列rename(2)
,将所有源名称依次附加到指定为目标的目录中:mv a b c d/
将生成rename("a", "d/a")
、rename("b", "d/b")
和rename("c", "d/c")
- 因此当然mv test test
会尝试调用rename("test", "test/test");
。这显然是一个错误,您不能将目录移动到其自身内部。
要解决您的问题,请将 mv 命令设置为新名称不同且不存在的条件(如果您有两个不同的文件,分别名为“Test”和“test”,您可能不想在未经询问的情况下替换第二个文件)。我没有对此进行测试,也没有在手机上输入它,它看起来会像这样:(new="$(echo "$old" | tr ...)"; [[ $new != $old && ! -e $new ]] && mv "$old" "$new"
注意引号,您不希望名称中的空格给您带来隐喻性的楔子)。