Linux重命名命令大写首字母

9

我正在编写一个Bash脚本来清理我的音乐文件。

我希望它能格式化所有文件名,并使它们更加规范化,因此通过一些互联网搜索,我编写了以下代码:

sed -i -e 's/[-_]/ /g' -e 's/ \+/ /g' -e **'s/\<[a-z]/\U&/g'** -e "s/$artist //g" -e "s/$album //g"

我曾经使用文本文件添加文件名,然后使用sed命令,但是我不知道如何将新的名称应用到文件上。

后来,我开始尝试使用rename命令,并成功地获得了完全相同的结果,唯独粗体部分未能实现,这部分应该是让每个单词的首字母大写。

rename 's/[-_]/ /g' * && rename 's/\s+/ /g' * && **rename 's/\s\w{1}/*A-Z*/g' *** && rename 's/^\d+[[:punct:]]\s//g' * && rename "s/$artist\s//g" * && rename "s/$album\s//g" * && rename "s/($ext)//g" *

现在,rename中的代码已经可以工作(至少是令人满意的),仅在SPACE字符后找到一个字母,但是替换却存在问题。我尝试了许多不同的方法,结果都是将焦点中的第一个字母交换成了这种情况下的A-Z。
在重命名手册页面上,它说要使小写大写,你需要使用's/a-z/A-Z/g',但很容易发现它只适用于找到a-z A-Z的情况。所以这就是我需要帮助的地方。
如果有人知道如何像sed示例那样进行操作,那就更好了。其中\<匹配每个单词的开头,因为目前我的rename命令不会应用于第一个单词,也不会应用于看起来像“Disc name [Disc 1]”的多个光盘,因为这是显而易见的原因。

我注意到你在帖子中一直“签名”。不要这样做。 - chrisaycock
如果你已经有了一个源文件名和目标文件名对的文本文件,那么 sed 's/^/mv /' textfile | sh 就足够了(尽管引用具有空格等特殊符号的文件名会使事情变得更加复杂;这只是一个概念证明,不是实际答案)。 - tripleee
2个回答

15

这个问题涉及到Perl,因为rename是用Perl编写的,并且重命名操作的指令也是Perl语句。

在一个s///中,为了让替换知道要插入哪个字母的大写版本,它必须从输入中“捕获”该字母。模式中的括号实现了这一点,将捕获的字母存储在变量$1中。在替换操作中,\u会将下一个字符转换为大写。

所以你可以这样做:

$ rename 's/\s(\w)/ \u$1/g' *

请注意,替换部分必须在大写字母前插入一个空格,因为模式包括空格,所以空格和原字母都将被替换。您可以使用\b来避免这种情况,它是一种零宽断言,仅匹配单词边界:

$ rename 's/\b(\w)/\u$1/g' *

还有,在这里你不需要{1},因为正则表达式中的\w(像其他符号一样)默认匹配一个字符。

最后,在rename(1)中的示例实际上是y/A-Z/a-z/,使用了y///操作符,而非s///y///是一个完全不同的操作符,它会将一组字母的所有出现替换为另一组;在这里对你来说没有用处,因为你只想让一些字符变成大写。


谢谢您提供这么详细的解释。它对我实现我的目标非常有帮助。我重新制定了整个替换公式,最终得出了rename 's/(\w)(\w{1,})/\u$1$2/g' *,它查找一个字母并将其捕获到$1中,仅当该字母后面至少跟着另一个字母时,然后将$1大写并使用$2打印出其余的单词。我在理解\b边界时遇到了一些问题,并且读到它不会匹配两个连续的字母字符,但\B确实可以匹配,但那也行不通......我现在不确定具体原因。 - Jompa
“1个或多个”是常见的需求,因此有它自己的符号+。您可以写\w+代替\w{1,} - Smylers
\b 匹配从单词字符到非单词字符的转换(反之亦然)。\B 是相反的,可以匹配任何其他位置。因此,/\b\w\B/ 匹配一个单词字符,该字符必须在其前面没有单词字符但在其后面有单词字符。这意味着s/\b(\w)\B/\u$1/g 与您的公式具有相同的效果,但不会打扰将单词的第二个及其后续字符取出来再放回去。 - Smylers
啊,我明白了。我尝试使用(\w)\B\w+,但这会将第一个字母大写并删除所有其他字母,但现在我明白了\B不需要任何后缀即可正常工作。如果我理解正确的话,它匹配所有它被设计匹配的内容? - Jompa
在我的Archlinux机器上,rename命令是util-linux软件包的一部分,它非常简单,只需要像mv一样传递2个参数,而且它根本不支持正则表达式。我不知道现在所有的发行版是否都是这样,但@Perleone和@Smylers提供的解决方案在我的机器上无法工作。 - Doron Behar
显示剩余2条评论

4
rename -nv 's{ (\A|\s) (\w+) }{$1\u$2}xmsg'

该代码寻找字符串开头的\A或空格后至少一个或多个字母字符(a-z,0-9,下划线)\w+。它将大写所有单词序列的第一个字符。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接