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


15

我有一台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

如何为大量的文件和目录实现这一目标?

我曾经看到过类似的问题:使用特殊字符批量重命名(或正确显示)文件

但这只能解决编码问题,我更喜欢如上所述的更严格的方法。

Answers:


14

如果要同时重命名文件目录,将会遇到一些问题。重命名一个文件很容易。但是您要确保目录也被重命名。您不能简单地说,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输出为null分隔,所以我们可以用它读read -d ''file变量。这样做有助于我们处理各种奇怪的文件名,包括带空格的文件名,甚至包括换行符。
  • 我们将使用获取文件目录dirname。不要忘记总是正确引用变量,否则任何带有空格或通配符的路径都会破坏此脚本。
  • 我们将使用获取实际的文件名(或目录名)basename
  • 然后,我们从$f使用Bash的字符串替换功能中删除所有无效字符。无效是指不是小写或大写字母,数字,斜杠(\/),点(\.),下划线或减号的任何内容。
  • 如果$f已经清除(清除的名称与当前名称相同),请跳过它。
  • 如果$new目录中已经存在$d(例如,您的文件名为,resume并且résumé在同一目录中),请发出警告。您不想重命名,因为在某些系统上mv foo foo会引起问题。除此以外,
  • 最后,我们将原始文件(或目录)重命名为其新名称。

由于这只会作用于最深的层次结构,因此重命名Motörhead/EncödingMotorhead/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.txtscheduletest本身。


1
您可能需要添加逻辑来处理mv已经存在的目标的情况,这种情况可能发生(1)如果您的文件已经清理干净(导致mv foo foo),或者(2)如果您的文件具有相同的名称,除了用于特殊字符(例如,,除之外mv Encöding Encoding,您还已有Encoding文件Encöding)。
斯科特(Scott)

好主意,谢谢。在这种情况下有什么具体建议吗?理所当然–以干净而理智的方式实现此目标比一开始看起来要困难。如果您有什么东西,当然可以随时进行编辑。
slhck

我认为考虑自动处理冲突是没有道理的–仅向用户识别冲突并让他处理即可。根据您的建议,我已经编辑了您的答案。
斯科特

+1,以将示例与“Encöding”一起使用!:-)
Marcel

三年后,我仍然回到这里。太有用了!:-)
AFR

15

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

这对我有用带有无效编码的波兰语文件名的文件夹起作用:

convmv -f cp1250 -t utf8 -r .

请注意,该命令实际上并没有重命名任何内容。添加--notest选项以真正重命名文件。


1
对于那些拥有静态集合(或没有多种字符集的混合对象)的用户,该convmv选项非常简单和完美。对于具有大量字符集的OP,可以将其与其他答案合并,因为它convmv似乎知道何时或何时未遇到正确的格式。通过遍历字符集via convmv --list,可以正确编码它们。

1
我的意思是,如果作为OP运行Debian服务器,这些天肯定会采用UTF8,在这种情况下,可以保留原始字母。我有一些北欧字符的文件夹,并使用:convmv -t utf8 --nfc -f iso-8859-1 --notest -r .--nfc要在OS X左右之前兼容Linux,只需键入即可convmv放弃(有用的)选项。

0

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

但是您可以使用MusicBrainz Picard之类的软件轻松避开该问题。

它能够识别音乐(音频指纹),从庞大的MusicBrainz数据库下载所有必要的数据(包括封面图像,如果有的话)以及移动文件,以便您的收藏可以适合您喜欢的任何模式。我已经使用了很多年,并且它在从Cyrilic到阿拉伯语的任何事物上都能完美地工作。当然(至少对于基于拉丁语的脚本而言),它也可以转换为ASCII。

使用这种方法,只要文件可读且完整,对您的收藏集的名称到底有多混乱/不好都没关系。

(我说过它是免费的吗?既有言论自由也有免费啤酒吗?软件和数据库都可以。)

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.