递归地从具有特定扩展名的所有文件中删除扩展名

递归地从具有特定扩展名的所有文件中删除扩展名

我有一个目录,其中有一堆子目录,其中有一堆扩展名为.no_sub.

我想将每个具有扩展名的文件重命名.no_sub为相同的名称并.no_sub删除。

所以foo.no_sub-> foo

我可以在 Bash 中执行此操作吗? (我使用的是Ubuntu 20.04)

答案1

使用标准findsh、 和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
  • 语法mvmv source target;
  • 我有时过于小心,但我也喜欢${fname}比仅仅更好$fname,因为不能有变量名称混淆。它只是扩展到变量的内容fname,即当前文件
  • 变量扩展${variable%pattern}扩展为变量内容,但通过后缀模式减少pattern

答案3

您可以使用 和 来执行此find操作xargs

find . -name '*.nosub' -print0 | xargs -0 rename .nosub ""

选项和-print0选项用于正确处理带空格的文件名。该命令是软件包提供的命令。find-0xargsrenameutil-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,实际上是移动文件。

相关内容