如何批量重命名无效编码的文件或批量替换无效编码字符?

如何批量重命名无效编码的文件或批量替换无效编码字符?

我有一台 Debian 服务器,正在为一家互联网广播电台托管音乐。我对文件名和路径感到困惑,因为很多文件的编码无效,例如:

./music/Bändname - Some Title - additional Info/B�ndname - 07 - This Title Is Cörtain, The EncÃding Not.mp3

理想情况下,我想删除所有非字母A-Z/a-z或数字0-9或破折号-/下划线的内容_...结果应该是这样的:

./music/Bndname-SomeTitle-additionalInfo/Bndname-07-ThisTitleIsCrtain,TheEncdingNot.mp3

如何对大量文件和目录进行批量实现?

我见过类似的问题:批量重命名(或正确显示)带有特殊字符的文件

但这只能修复编码,我更喜欢如上所述的更严格的方法。

答案1

如果你想重命名文件,你会遇到一些问题目录。重命名文件很容易。但您要确保目录也重命名。您不能简单地mv Motörhead/Encöding Motorhead/Encoding因为Motorhead在调用时不存在。

因此,我们需要对所有文件和文件夹进行深度优先遍历,然后仅重命名当前文件或文件夹。以下内容适用于find我的 OS X 上的 GNU 和 Bash 4.2.42。

#!/usr/bin/env bash
find "$1" -depth -print0 | while IFS= read -r -d '' file; do
  d="$( dirname "$file" )"
  f="$( basename "$file" )"
  new="${f//[^a-zA-Z0-9\/\._\-]/}"
  if [ "$f" != "$new" ]      # if equal, name is already clean, so leave alone
  then
    if [ -e "$d/$new" ]
    then
      echo "Notice: \"$new\" and \"$f\" both exist in "$d":"
      ls -ld "$d/$new" "$d/$f"
    else
      echo mv "$file" "$d/$new"      # remove "echo" to actually rename things
    fi
  fi
done

new="${f//[\\\/\:\*\?\"<>|]/}"如果您想要替换 Windows 无法处理的任何内容,您可以使用来更改正则表达式。

将此脚本另存为rename.sh,使用 使其可执行chmod +x rename.sh。然后,像 一样调用它rename.sh /some/path

确保解决所有文件名冲突(“ Notice”声明)。

如果你是绝对肯定它进行了正确的替换,echo从脚本中删除了实际重命名的内容,而不仅仅是打印它所做的事情。

为了安全起见,我建议先在一小部分文件上进行测试。


选项说明

解释一下这里发生的事情:

  • -depth将确保目录是深度优先递归的,因此我们可以从末尾“卷起”所有内容。通常,find遍历方式不同(但不是广度优先)。
  • -print0确保find输出以空分隔,这样我们就可以将其读read -d ''file变量。这样做可以帮助我们处理各种奇怪的文件名,包括带空格的文件名,甚至换行符的文件名。
  • 我们将使用 获取文件的目录dirname。不要忘记始终正确引用变量,否则任何带有空格或通配符的路径都会破坏此脚本。
  • 我们将使用 获取实际的文件名(或目录名)basename
  • 然后,我们使用 Bash 的字符串替换功能删除所有无效字符$f。无效字符是指除小写或大写字母、数字、斜线 ( \/)、点 ( \.)、下划线或减号连字符之外的任何字符。
  • 如果$f已经干净(清理后的名称与当前名称相同),则跳过它。
  • 如果$new目录中已经存在$d(例如,您有同名文件resume,并且résumé位于同一目录中),则发出警告。您不想重命名它,因为在某些系统上mv foo foo会导致问题。否则,
  • 最后我们将原始文件(或目录)重命名为新名称

由于这只会对最深的层次结构起作用,因此重命名分Motörhead/Encöding两个Motorhead/Encoding步骤完成:

  1. mv Motörhead/Encöding Motörhead/Encoding
  2. mv Motörhead Motorhead

这确保所有替换都按照正确的顺序完成。


示例文件和测试运行

我们假设基础文件夹中有一些文件名为test

test
test/Motörhead
test/Motörhead/anöther_file.mp3
test/Motörhead/Encöding
test/Randöm
test/Täst
test/Täst/Töst
test/with space
test/with-hyphen.txt
test/work
test/work/resume
test/work/résumé
test/work/schedule

以下是在调试模式下运行的输出(在echo前面mv),即将调用的命令和碰撞警告:

mv test/Motörhead/anöther_file.mp3 test/Motörhead/another_file.mp3
mv test/Motörhead/Encöding test/Motörhead/Encoding
mv test/Motörhead test/Motorhead
mv test/Randöm test/Random
mv test/Täst/Töst test/Täst/Tost
mv test/Täst test/Tast
mv test/with space test/withspace
Notice: "resume" and "résumé" both exist in test/work:
-rw-r—r--  …  …  test/work/resume
-rw-r—r--  …  …  test/work/résumé

with-hyphen.txt请注意,、schedule和其本身都没有消息test

答案2

我知道这不是你想要的,但如果你知道原始编码,也许你可以使用convmv将编码更改为 UTF-8,这应该可以解决大多数问题。

这对我在一个包含一些无效编码的波兰文件名的文件夹中起作用:

convmv -f cp1250 -t utf8 -r .

请注意,此命令实际上并不重命名任何内容;添加--notest选项来真正重命名文件。

答案3

我知道,您问的是重命名的问题。

但你可以很容易地使用类似软件来避开这个问题MusicBrainz Picard

它能够识别音乐(音频指纹),从巨大的音乐大脑数据库并移动文件,这样您的收藏就可以符合您喜欢的任何模式。我已经使用它多年了,它总是能完美地处理从西里尔文到阿拉伯文的任何内容;当然(至少对于基于拉丁文的脚本)它也可以转换为 ASCII。

采用这种方法,只要文件可读且完整,您的收藏集的名称有多混乱/糟糕就并不重要。

(我有没有说过它是免费的?既指言论自由,又指免费啤酒?软件和数据库都是免费的?)

相关内容