关于linux:如何将文件名从“find”传递到“tr”?

How to pass filenames from “find” to “tr”?

本问题已经有最佳答案,请猛点这里访问。

我正在尝试学习一些命令是如何工作的,我想制作一个简单的脚本,将文件名中的大写字母改为小写字母。我创建了那个脚本:

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

它可以工作,但它只使用echo-lowercced文件名进行写入,而不更改它们。另一方面,这段代码:

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

就好像我只会使用:

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

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


正如@tink指出的那样,如果要重命名文件,则需要实际调用mvtr只是转换字符串(坦率地说,如果您使用的是bash 4.0或更高版本(通过参数扩展语法提供本机大小写转换),那么没有充分的理由使用它来在大小写之间转换shell变量。

usingfind的complex actions部分显示了一种与您已经运行的代码非常相似的方法:

1
2
3
4
5
6
7
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操作来避免很多复杂性:

1
2
3
4
5
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 *更可靠,因为它不依赖于shell globbing;并且-exec ... _ {} +-exec ... _ {} \;更有效,因为它将多个名称传递给一个命令,而不是为找到的每个名称启动单独的bash副本。


好。。。tr就是这样做的;把一个字符集翻译成另一个字符集,这里是从上到下。要实际更改文件名,需要使用mv

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