我使用此命令递归地重命名文件:
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 f
仅find
考虑常规文件,即不考虑目录等。
对于更便携的解决方案:
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
通配模式**
匹配任意数量的中间子目录。这种特殊模式是通过globstar
shell 选项启用的。初始./*/
确保我们只查找当前目录的子目录,而不是当前目录本身。
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/'