【问题标题】:How to delete numbers, dashes and underscores in the beginning of a file name如何删除文件名开头的数字、破折号和下划线
【发布时间】:2016-10-20 13:45:10
【问题描述】:

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

songone.mp3
songtwo.mp3
songthree.mp3

【问题讨论】:

    标签: linux bash unix filenames


    【解决方案1】:

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

      1234563 :(shopt -s extglob; for fname ...))。
    • extglob 语法是常规 glob 语法的扩展,很少有人熟悉,但仍不如真正的正则表达式强大。


    使用 Bash 的 regex-matching operator, =~:

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

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

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

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

    【讨论】:

      【解决方案2】:

      这可以使用扩展通配符来完成:

      $ 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)代表“模式的零个或多个匹配”,实际模式是连字符、下划线和数字的括号表达式。

      备注

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

      • *() 表达式需要 extglob shell 选项。正如所指出的,如果您以后不想扩展 glob,则必须使用 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
        

        这确保有一些东西要重命名。

      【讨论】:

      • 请始终使用mv -i 进行此类批量移动,以避免在类似名称的文件(或导致其执行意外操作的拼写错误,或...)的情况下意外丢失数据。
      • 您可能需要遍历 [-_[:digit:]]* 以避免不必要地将不匹配的文件移动到自己身上。
      • @tripleee 好点。问题是“所有文件名不寻常”,但为了获得更普遍适用的解决方案,我添加了一个备注。
      • 使用mv --mv "./$fname"for fname in ./*.mp3,以防文件名以连字符开头...
      • @gniourf_gniourf 额外相关,因为我们正在寻找完全一样的文件,谢谢!更新中。
      【解决方案3】:

      你也可以这样做:

      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&gt;/dev/null 用于忽略已转换/正确文件名的 mv 错误。


      注意:

      这也将递归地更改子文件夹中的文件名。

      【讨论】:

        猜你喜欢
        • 2011-08-29
        • 1970-01-01
        • 2015-07-18
        • 1970-01-01
        • 2017-10-16
        • 1970-01-01
        • 2015-08-13
        • 1970-01-01
        • 2018-11-21
        相关资源
        最近更新 更多