如何删除文件名开头的数字,短划线和下划线

时间:2016-06-19 01:57:33

标签: linux bash unix filenames

我有数千个mp3文件,但都有不寻常的文件名,例如1-2songone.mp32songtwo.mp32_2_3_songthree.mp3。我想删除这些文件开头的所有数字,破折号和下划线,并得到结果:

songone.mp3
songtwo.mp3
songthree.mp3

3 个答案:

答案 0 :(得分:5)

这可以使用扩展的globbing来完成:

$ ls
1-2songone.mp3  2_2_3_songthree.mp3  2songtwo.mp3
$ shopt -s extglob
$ for fname in *.mp3; do mv -- "$fname" "${fname##*([-_[:digit:]])}"; done
$ ls
songone.mp3  songthree.mp3  songtwo.mp3

这使用parameter expansion${fname##pattern}fname的开头删除最长的匹配。作为模式,我们使用*([-_[:digit:]]),其中*(pattern)代表&#34;模式&#34;的零或多个匹配,实际模式是hyhpens,下划线和数字的括号表达式。< / p>

<强>说明

  • --之后的mv表示move的选项结束,并确保以-开头的文件名不会被解释为选项。

  • *()表达式需要extglob shell选项。如上所述,如果您以后不想要扩展的全局,则必须使用shopt -u extglob重新设置它。

  • 根据Gordon Davisson的评论:如果您有1file.mp32file.mp3之类的内容,这将会破坏文件。为避免这种情况,您可以使用mv -i(或--interactive),它会在覆盖文件之前提示您,或mv -n(或--noclobber),这样就不会覆盖任何文件。

  • triplee指出,如果他们不以斜线,下划线或数字开头,则会不必要地将文件移动到自己身上。为避免这种情况,我们只能使用

    迭代匹配的文件
    for fname in [-_[:digit:]]*.mp3; do mv -- "$fname" "${fname##*([-_[:digit:]])}"; done
    

    确保有重命名的内容。

答案 1 :(得分:4)

Benjamin W.'s answer有用且高效,但有两个缺点:

  • 它需要设置全局shell选项extglob,之后应该将其恢复到之前的值(替代方法是以创建额外进程为代价,使用子shell (shopt -s extglob; for fname ...))。

  • extglob语法是常规glob语法的扩展,很少有人熟悉,但仍然比真正的正则表达式更强大。

使用Bash&#39; regex-matching operator, =~

for f in *.mp3; do [[ $f =~ ^[0-9_-]+(.+)$ ]] && echo mv "$f" "${BASH_REMATCH[1]}"; done

删除echo以执行实际重命名。

  • $f =~ ^[0-9_-]+(.+)$匹配文件名开头的最长非数字,连字符和下划线序列,后跟括号内的子表达式(捕获组)中捕获的任何非空字符序列。

  • 如果匹配成功(&&),则调用mv命令,捕获的子表达式 - 可通过特殊BASH数组变量{{1}的元素1访问} - 形成目标文件名。

答案 2 :(得分:0)

您也可以这样做:

find . -type f -name "*.mp3" -print0 | while read -r -d '' line
do
 mv "$line" "$( sed -E 's!(.*)/[^[:alpha:]]*([[:alpha:]].*mp3)$!\1/\2!' <<<"$line")" 2>/dev/null 
done

我想,使用sed可以让你更好地控制正则表达式。此外,2>/dev/null用于忽略已转换/正确文件名的mv错误。

注意:

这将以递归方式更改子文件夹之间的文件名。