![从文件名中递归删除方括号及其包围的内容](https://linux22.com/image/214600/%E4%BB%8E%E6%96%87%E4%BB%B6%E5%90%8D%E4%B8%AD%E9%80%92%E5%BD%92%E5%88%A0%E9%99%A4%E6%96%B9%E6%8B%AC%E5%8F%B7%E5%8F%8A%E5%85%B6%E5%8C%85%E5%9B%B4%E7%9A%84%E5%86%85%E5%AE%B9.png)
我正在尝试递归地删除括号及其内容 ( [.*]
)(如果它位于文件名的开头)。
例如,[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