我正在尝试学习几个命令的工作方式,我想制作一个简单的脚本,将文件名中的大写字母更改为小写。 我创建了该脚本:
find * -exec bash -c \
'echo "${1##*/}" | tr "[:upper:]" "[:lower:]";' _ {} \;
它可以工作,但是只写回声小写的文件名,而不更改它们。另一方面,这段代码:
find * -exec bash -c \
'tr "[:upper:]" "[:lower:]";' _ {} \;
表现得好像我只会使用:
tr "[:upper:]" "[:lower:]"
因此,我想学习和理解如何传递从find
获得的文件名,并使用tr
对它们进行任何处理。已经去过手册和Google,什么也没找到。
答案 0 :(得分:0)
好吧……tr
就是这么做的;将一个字符集转换为另一个字符集,这里从上到下。要实际更改文件名,您需要使用mv
。
捕获实际上将要更改的名称,然后在这些名称上使用mv
;您不能只为每个文件都使用mv
,因为这样会给您错误信息,类型为mv: 'blah' and 'blah' are the same file
...
答案 1 :(得分:0)
与@tink points out一样,如果要重命名文件,则需要实际调用mv
。 tr
只是翻译字符串(坦率地说,如果您使用的是bash 4.0或更高版本(has native case conversion available via parameter expansion syntax),没有充分的理由使用它在大写和小写之间转换shell变量)。
Complex Actions section of UsingFind显示了一种与您已经在运行的代码非常相似的方法:
find . -depth -exec bash -c '
for old_name; do
new_name=$(tr "[:upper:]" "[:lower:]" <<<"$old_name")
[[ $old_name = "$new_name" ]] && continue
mv -- "$old_name" "$new_name"
done
' _ {} +;
...尽管就我个人而言,我倾向于通过在父shell中执行mv
操作来避免很多复杂性:
while IFS= read -r -d '' old_name; do
new_name=$(tr "[:upper:]" "[:lower:]" <<<"$old_name") # or new_name=${old_name,,}
[[ $old_name = "$new_name" ]] && continue
mv -- "$old_name" "$new_name"
done < <(find . -type f -print0)
请注意,在第一种情况下,我们使用的是find . -exec {} +
。使用find .
比find *
更可靠,因为它不依赖于外壳程序。并且-exec ... _ {} +
比-exec ... _ {} \;
更有效率,因为它将多个名称传递给一个命令,而不是为找到的每个名称启动单独的bash副本。