如何将文件名从“查找”传递到“ tr”?

时间:2018-10-28 17:57:02

标签: linux shell

我正在尝试学习几个命令的工作方式,我想制作一个简单的脚本,将文件名中的大写字母更改为小写。 我创建了该脚本:

find * -exec bash -c \
     'echo "${1##*/}" | tr "[:upper:]" "[:lower:]";' _ {} \;

它可以工作,但是只写回声小写的文件名,而不更改它们。另一方面,这段代码:

 find * -exec bash -c \
     'tr "[:upper:]" "[:lower:]";' _ {} \;

表现得好像我只会使用:

tr "[:upper:]" "[:lower:]"

因此,我想学习和理解如何传递从find获得的文件名,并使用tr对它们进行任何处理。已经去过手册和Google,什么也没找到。

2 个答案:

答案 0 :(得分:0)

好吧……tr就是这么做的;将一个字符集转换为另一个字符集,这里从上到下。要实际更改文件名,您需要使用mv

捕获实际上将要更改的名称,然后在这些名称上使用mv;您不能只为每个文件都使用mv,因为这样会给您错误信息,类型为mv: 'blah' and 'blah' are the same file ...

答案 1 :(得分:0)

@tink points out一样,如果要重命名文件,则需要实际调用mvtr只是翻译字符串(坦率地说,如果您使用的是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副本。