从文件名中递归删除方括号及其包围的内容

从文件名中递归删除方括号及其包围的内容

我正在尝试递归地删除括号及其内容 ( [.*])(如果它位于文件名的开头)。

例如,[Author1]BookName.epub应重命名为BookName.epub.

但是,当括号不在开头时(例如BookName[Author1].epub),什么都不应该改变。

这个命令有效find . -type f -exec rename -v "s/\[.*\]//g" '{}' \;

但是,当我添加^以确保括号位于文件名 ( ) 的开头时find . -type f -exec rename -v "s/^\[.*\]//g" '{}' \;,它不起作用。我所说的“不起作用”是指命令成功运行,但文件名未更改。没有错误,没有消息。

这里可能有什么问题?

答案1

重命名文件时,您需要确保仅更改文件的名称(路径的最后一个组成部分)

对于 perl rename 的某些变体,可以使用该-d选项来完成。

find . -depth -name '*\[*\]*' -type f -exec rename -v -d 's/^\[.*?\]//s' {} +

.*另请参见: .*?so的非贪婪变体,./foo[x]bar/[a]b[c]d./foo[x]bar/b[c]d不是./foo[x]bar/d(与\[.*\]匹配[a]b[c]),并且s标志 so.也匹配换行符,因为我们在这里处理文件路径,而不是文本行。

(因此文件-depth在它们所在的目录之前被重命名)在这里并不是绝对必要的,因为您只是重命名常规文件,但最好记住在重命名文件时养成包含它的习惯,因为它通常是必要的。

如果您rename不支持该-d选项,您可以执行以下操作:

find . -depth -name '*\[*\]*' -type f -exec rename '
  s:(?<!/)\[[^/]*?\](?=[^/]*\z)::s' {} +

也就是说,[<characters-other-than-slash>]如果它们后面跟着 a /,并且后面只跟非斜杠字符,直到路径末尾 ( \z),则将其删除。

答案2

要查看这里发生的情况,您应该使用该-print操作(并暂时停止rename尝试使用该标志更改任何内容-n):

find . -type f -print -exec rename -n 's/^\[.*\]//g' {} \;

查看命令发出的文件名。没有一个会匹配您的模式,因为它们都以./.

相反,您需要在该行的[ … ]最后一个之后立即进行匹配/。这个更简单的版本假设/[ … ]目录组件中没有匹配项:

find . -type f -exec rename -n 's!(.*/)\[.*?]!$1!s' {} +

这个更复杂的版本正确地处理了这种可能性(并且也完全接受了更简单的场景):

find . -type f -exec rename -n 's!(.*/)\[[^/]*?]([^/]*)$!$1$2!s' {} +

稀土细分:

  • s!x!y!s- 匹配 REx并用文本替换y。尾随s允许匹配跨越多行
  • (.*/)- 尽可能多地匹配直到并包括/.将此称为第一场分组比赛$1
  • \[- 匹配文字[
  • .*?]- 尽可能少地匹配直到并包括]
  • ([^/]*)- 如果不是的话,尽可能多地匹配/。称这场比赛为$2
  • $- 匹配 ”行结束
  • $1$2- 替换我们与组匹配的所有内容$1$2

无论哪种情况,仅当您确定它正在执行您想要的操作时才将其更改-n为背面。-v

答案3

如果有人觉得舒服FDrnr,命令为:

fd -t f -x rnr -f --no-dump '\[.*\]' ''

不使用-f就像使用一样--dry-run--dry-run是默认的。

如果您不使用--no-dump并拥有转储文件,那么您甚至可以撤消重命名操作

相关内容