递归重命名排除当前目录

递归重命名排除当前目录

我使用此命令递归地重命名文件:

find -iname \*.bak | rename 's/.bak/.old/'

但我想排除当前目录。例子:

.bak
dir1/.bak
dir2/.bak
...

我想要这个之后:

.bak
dir1/.old
dir2/.old
...

答案1

使用find支持-mindepth谓词的 a:

 find . -mindepth 2 -type f -name '*.bak' | rename 's/\.bak$/.old/'

谓词-mindepth允许您定义可以进行匹配的最小搜索深度。深度 0 是根搜索路径本身 ( .),深度 1 是紧邻根搜索路径下方的任何内容(例如./somename),深度 2 是紧邻根搜索路径下方的任何内容(例如./somename/other),等等。

-iname请注意,不需要区分大小写的匹配,因为rename无论如何您都不会重命名具有其他类型的文件名后缀大写的文件,因此我将其更改为测试-name。我还修复了您的rename调用,以便bak名称中其他位置带有字符串的文件(例如rebak.bak)不会以奇怪的方式重命名(例如,重命名为r.old.bak)。

我还添加了-type ffind考虑常规文件,即不考虑目录等。

对于更便携的解决方案:

find . -mindepth 2 -type f -name '*.bak' -exec sh -c '
    for pathname do
        mv "$pathname" "${pathname%.bak}.old"
    done' sh {} +

这不依赖于rename效用。

find . -mindepth 2 -type f -name '*.bak' -exec rename 's/\.bak$/.old/' {} +

rename直接从调用find

有关的:


使用bash,您可以find完全跳过并执行

shopt -s globstar dotglob

rename 's/\.bak$/.old/' ./*/**/*.bak

通配模式**匹配任意数量的中间子目录。这种特殊模式是通过globstarshell 选项启用的。初始./*/确保我们只查找当前目录的子目录,而不是当前目录本身。

shelldotglob选项确保我们将隐藏名称与模式相匹配。

然而,上面的命令不会专门挑选常规文件(但你的find命令也不会)。为此,请使用循环:

shopt -s globstar dotglob

for pathname in ./*/**/*.bak; do
    [[ ! -f $pathname ]] && continue
    rename 's/\.bak$/.old/' "$pathname"
done

这也会将符号链接重命名为常规文件。

答案2

尝试这个

find -iname \*.bak -not -path "./.bak" | rename 's/.bak/.old/'

相关内容