我有一个目录,其中有一堆子目录,其中有一堆扩展名为.no_sub
.
我想将每个具有扩展名的文件重命名.no_sub
为相同的名称并.no_sub
删除。
所以foo.no_sub
-> foo
。
我可以在 Bash 中执行此操作吗? (我使用的是Ubuntu 20.04)
答案1
使用标准find
、sh
、 和mv
:
find . -type f -name '*.no_sub' -exec sh -c '
for pathname do
mv -- "$pathname" "${pathname%.no_sub}"
done' sh {} +
.no_sub
这将查找当前目录中或当前目录下名称以 string 结尾的任何常规文件。对于批量的这些路径名,将调用一个简短的内联 shell 脚本。该sh -c
脚本迭代给定的一批路径名,并通过删除文件名后缀来重命名每个路径名.no_sub
。文件名后缀的删除是使用标准${variable%suffix}
参数扩展完成的。
不检查文件名冲突。
这是相似的到Marcus Müller 提供的解决方案因为单个文件的重命名以相同的方式发生,但用于find
生成循环的路径名列表,其方式将拾取隐藏名称并包含显式文件类型过滤器以仅迭代常规文件。
也可以看看:了解“find”的 -exec 选项
由于我们知道赋予内联脚本的每个文件名都以 结尾,因此如果我们愿意,.no_sub
我们可以避免在其中重复:.no_sub
find . -type f -name '*.no_sub' -exec sh -c '
for pathname do
mv -- "$pathname" "${pathname%.*}"
done' sh {} +
答案2
使用 shell 的功能获取所有文件,然后使用常用工具重命名它们
shopt -s nullglob ## as recommended and explained in the comments
shopt -s globstar
shopt -s dotglob
for fname in **/*.no_sub ; do
mv -- "${fname}" "${fname%.no_sub}"
done
这里,
shopt -s globstar
**
作为递归 glob启用shopt -s dotglob
能够发现.*.no_sub
- 循环
for
是一种特殊字符安全的方式来遍历所有文件(永远不要解析ls
它) - 语法
mv
是mv source target
; - 我有时过于小心,但我也喜欢
${fname}
比仅仅更好$fname
,因为不能有变量名称混淆。它只是扩展到变量的内容fname
,即当前文件 - 变量扩展
${variable%pattern}
扩展为变量内容,但通过后缀模式减少pattern
答案3
您可以使用 和 来执行此find
操作xargs
:
find . -name '*.nosub' -print0 | xargs -0 rename .nosub ""
选项和-print0
选项用于正确处理带空格的文件名。该命令是软件包提供的命令。find
-0
xargs
rename
util-linux
答案4
使用 POSIX find
:
find . -type f -name '*.no_sub' \
-exec perl -le '
rename $_, s/\.no_sub$//r
for @ARGV;
' {} +;
我们查找名称以 结尾的常规文件.no_sub
,并将名称放在perl
.
然后,Perl 调用其内置的重命名命令并删除尾随扩展名 .no_sub,实际上是移动文件。