如何使用此查找和重命名命令来处理子目录?

如何使用此查找和重命名命令来处理子目录?

可能的重复:
递归重命名文件和目录

我有一个很大的音乐文件目录,该目录经常随着文件和目录的变化而变化。我的偏好是确保文件和目录名称中不包含空格,因此我将它们全部替换为下划线。

我进入主目录并运行以下命令:

$ find -type d -exec rename 'y/\ /\_/' {} \;

问题是,当有子目录时,这个命令似乎会丢失并且会返回错误。所以如果我有以下目录结构:

在此输入图像描述

...如果我运行该命令,我会收到以下错误:

$ find -type d -exec rename 'y/\ /\_/' {} \;
find: `./Test 02': No such file or directory
find: `./Test 01': No such file or directory
find: `./Test 03': No such file or directory

然后结果是我的目录结构如下所示。请注意,子目录中仍然有空格:

在此输入图像描述

如果我再次运行该命令,我会收到这些错误,即使它看起来可能重命名了有问题的目录:

$ find -type d -exec rename 'y/\ /\_/' {} \;
find: `./Test_01/Test A': No such file or directory
find: `./Test_01/Test C': No such file or directory
find: `./Test_01/Test B': No such file or directory

最后,我再次运行该命令,并且没有收到任何错误,并且所有目录和子目录都按照我想要的方式命名:

在此输入图像描述

显然,当我有多个子目录时,这需要运行命令更多次,这可能会变得乏味。

我怎样才能使这个命令只需要运行一次,它就会一次性重命名所有目录和子目录?

我的最终目标是将其包含在 Bash 脚本中,以便我可以将它与其他类似的内务命令一起运行,因此我需要它不返回错误或需要我提供更多输入。另外,如果有影响的话,我正在运行 Ubuntu 12.04。

答案1

发生的情况如下:

  • find找到匹配的目录./Test 02
  • findrename在该目录上执行命令。
  • rename重命名Test 02Test_02.
  • find尝试下降到目录中Test 02。但它已经不存在了。

解决此问题的最简单方法是告诉find以相反的方式工作:首先在目录内查找匹配项,然后检查目录本身是否匹配。这就是该-depth选项的作用。

如果您只添加-depth,您将遇到另一个问题,即当find到达时Test 01/Test A,它会调用rename 'y/\ /\_/' 'Test 01/Test A',它会尝试将该目录重命名为Test_01/Test_A。这将失败,因为没有名为 的目录Test_01。一个简单的解决方法是使用该-execdir选项,该选项在目录rename内部调用Test 01Test A作为参数传递。您可以通过在一批中传递多个参数来加快速度rename,使用+而不是;终止-execdir命令。

find -depth -name '* *' -type d -execdir rename 'y/ /_/' {} +

或者,使用这个简短但神秘的 zsh 命令:

autoload zmv
zmv -Qw '**/*(/D)' '$1${2// /_}'

zmv功能根据模式重命名文件。源模式为,它递归地匹配所有子目录中的**/*所有文件 ( ) ( )。这***/全局限定符(由选项激活-Q)表示仅匹配目录 ( /) 并包含点文件 ( D)。该-w选项为源模式中的每个通配符创建反向引用。替换以$1指定第一个通配符的匹配开始(对于**,这包括最后一个/),然后是${2// /_},它$2(匹配的内容*)被修改为用 替换所有空格字符_。添加-v选项来查看命令的作用,您会注意到它像 一样首先遍历深度find -depth

相关内容