我的音乐库包括以以下模式命名的文件夹 :
METAGENRE - Subgenre(s) - ARTIST - Album (year)
我想在文件夹名称中为我拥有其整个唱片目录的一些乐队/艺术家切换年份和专辑“标签”,因此它按发行时间顺序而不是专辑名称排序。与此同时,我还可以删除年份标签周围的括号,即:
METAGENRE - Subgenre(s) - ARTIST - year Album
例如 :METAL - Black, Français - PESTE NOIRE - Split (2018)
应该变成:METAL - Black, Français - PESTE NOIRE - 2018 Split
我对 shell 只有很少的经验。在此处和其他地方寻求帮助,我可以想出这个但不完美的单行(“echo”用于在重命名之前进行测试并避免潜在的地狱,为了可读性,我还在这里重新转录了几行):
% for f in *PESTE\ NOIRE* ;
do echo
mv "$f"
"$(echo $f | sed `s/- ([A-Za-z]+) \(([0-9]{4})\)$/- \2 \1/p`)"
;
done
在终端中运行此命令时,我得到的只是:
zsh: missing identifier after `+'
我究竟做错了什么 ?
编辑:(使用 ' 而不是 ` 引号)
% for f in *PESTE\ NOIRE* ; do echo mv "$f" "$(echo $f | sed 's/- ([A-Za-z]+) \(([0-9]{4})\)$/- \2 \1/')" ; done
有效,但现在我收到另一个错误:
sed: 1: "s/- ([A-Za-z]+) \(([0-9 ...": \2 not defined in the RE
因此 :
% for f in *PESTE\ NOIRE* ; do echo mv "$f" "$(echo $f | sed 's/- \([A-Za-z]+\) \\\(\([0-9]{4}\)\\\)$/- \2 \1/')" ; done
不返回错误,但文件夹保持未重命名状态。
答案1
在 中zsh
,您可以用来zmv
重命名文件:
autoload -Uz zmv # best in ~/.zshrc
zmv -n '(*PESTE NOIRE*-)(*) \((<1900-2100>)\)' '$1 $3$2'
删除-n
(试运行)以实际执行此操作。
您的代码中的一些问题:
`...`
是 sh/csh 中已弃用的命令替换形式,并且与现代$(...)
形式(来自ksh
)一样,也需要引用。但不应该使用它,因为它本身存在许多问题。无论如何,它不用于引用文本,仅用于扩展某些命令的输出。对于sed
往往包含诸如\
或之类字符的代码,最好的引号$
是单引号 ('...'
),在类似于 Bourne 的 shell(包括 zsh)中,shell 不会对其中的任何字符进行特殊处理。- 要逐字打印一些文本,请使用
print -r - $f
(ksh 样式,尽管您需要 ksh 中的引号) 或printf '%s\n' $f
(POSIX 样式,也需要 sh 中的引号),或echo -E - $f
(zsh
-特定) 不echo $f
破坏$f
以-
或包含开头的值反斜杠。另请参阅<<< $f
此处字符串语法。 +
,{4}
和(...)
是扩展(或perl)正则表达式运算符,因此您需要-E
或, 在支持的情况下-P
的选项sed
。基本的正则表达式等效项是\{1,\}
,\{4\}
and\(...\)
(这解释了为什么 your\2
不匹配)。一些sed
实现还支持\+
.[A-Za-z]
A
匹配在andZ
和a
and之间排序的字符z
,具体取决于 sed 实现,它可能会或可能不会匹配ç
orœ
,它不与 zsh 自己的 glob 匹配。ź
可能会排序,z
因此被排除在外。其他文字中的字母也是如此。用于[[:alpha:]]
匹配字母(或更普遍地用于人类语言单词中的字符)。许多专辑可能有空格或数字或.
,'
...用于[^-]
除此之外的任何字符-
可能是更好的方法。或者像zmv
上面一样,依赖于前面的内容*
是贪婪的这一事实。- 请记住,这
sed
是基于行和基于文本的,因此不会将文件名作为一个整体进行处理,而是单独处理文件名的每一行(仅对于包含换行符或非字符(例如编码中的字符)的文件名来说是一个问题区域设置以外的字符集)。 - 在命令参数中使用变量数据时,需要
--
标记选项的结尾。如果它以 开头,mv $f ...
则将视为一个选项。$f
-
因此,如果您必须使用sed
(但您肯定不会在 zsh 中使用),那么解决这些问题将如下所示:
for old in *'PESTE NOIRE'*; do
new=$(print -r - $f | sed '
:1
$!{
N;b1
}
s/\(.*-\)\(.*\) ([[:digit:]]\{4\})$/\1 \3\2/'
) && [[ $old != $new ]] &&
mv -i -- $old $new
done
答案2
使用单引号 (') 而不是反引号 (`) 来引用 sed 表达式