![如何使用 shell 交换文件名中的单词?](https://linux22.com/image/56981/%E5%A6%82%E4%BD%95%E4%BD%BF%E7%94%A8%20shell%20%E4%BA%A4%E6%8D%A2%E6%96%87%E4%BB%B6%E5%90%8D%E4%B8%AD%E7%9A%84%E5%8D%95%E8%AF%8D%EF%BC%9F.png)
我的一个客户是一所学校。在其文件服务器上,所有项目都有一个具有相同命名方案的目录。
<姓氏>、<名字> <第二名>? - <项目描述>
例如:
Miller, John Andrew - 长项目描述 Willis, Bruce - 描述,可能带有逗号 刘易斯,玛丽·简 - 描述 - 包括减号
新的命名约定是:
<名字> <第二名>? <姓氏> - <项目描述>
例如:
John Andrew Miller - 长项目描述 布鲁斯·威利斯 - 描述,可能带有逗号 玛丽·简·刘易斯 - 描述 - 包括减号
现在如何将所有现有文件夹批量重命名为新约定?
答案1
由于文件名的描述部分可以包含模式-
(两个空格之间的连字符),因此您可以将其更改为某个符号不出现在描述部分。我选择了£
,但这纯粹是任意的。
rename 's/ - /£/' *
rename 's/([^,]*), ([^£]*)£/$2 $1 - /' *
s/ - /£/' tells rename to replace the first instance of
- it finds with
£ . The second command is a bit more complicated. Parenthases (
() ) are used to group selections together -- so everything that matches the pattern within the first set of parens can be called later as
$1 (all the way up to
$9 ).
[^,] means 'any character, except for
,';
means 'zero or more of the previous character';
[^,]` 表示“零个或多个除逗号之外的任何字符”。由于重命名默认是贪婪的,因此它会匹配尽可能长的字符串。
我认为其余的事情就很自然了。
如果您不确定符号是否出现在文件名中的任何位置,只需运行:
printf '%s\n' *£*
如果你有 perl-rename:
rename 's/([^,]*), (.*) - /$2 $1 - /' *
如果文件名的描述部分包含-
(即-
两个空格之间的 a),这将中断。
您应该使用该-n
标志进行测试,该标志不会重命名任何文件,但会显示它的内容会完成了:
rename -n 's/([^,]*), (.*) - /$2 $1 - /' *
答案2
就匹配而言,您需要非常小心才能构建健壮的东西。例如,假设名字和中间名
- 必须以字母开头
- 可以包含连字符(但不能包含其他标点符号或空格)
你的名字模式变成了类似[[:alpha:]][[:alpha:]-]*
.然后,您可以创建一个可选的以空格分隔的中间名,因为((?: [[:alpha:]][[:alpha:]-]*)?)
额外的非捕获组结构有助于在中间名为空时保持捕获组编号的连续性。例如使用基于 perl 的重命名命令将它们放在一起
rename -nv -- 's/(^[^,]*), ([[:alpha:]][[:alpha:]-]*)((?: [[:alpha:]][[:alpha:]-]*)?)/$2$3 $1/' *
或(允许字段之间有更通用的空格而不是单个空格)
rename -nv -- 's/(^[^,]*),\s+([[:alpha:]][[:alpha:]-]*)((?:\s+[[:alpha:]][[:alpha:]-]*)?)/$2$3 $1/' *
该-n
开关是无操作的,即在删除之前它不会实际执行重命名。如果您没有基于 perl 的重命名,您可以使用perl
和的组合mv
。