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

Afr*_*Afr 17 linux encoding batch bulk

我有一个 debian 服务器,我正在为一个网络广播电台托管音乐。我在文件名和路径方面遇到问题,因为很多文件的编码无效,例如:

./music/Bändname - Some Title - additional Info/B?ndname - 07 - This Title Is Cörtain, The EncÃding Not.mp3
Run Code Online (Sandbox Code Playgroud)

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

./music/Bndname-SomeTitle-additionalInfo/Bndname-07-ThisTitleIsCrtain,TheEncdingNot.mp3
Run Code Online (Sandbox Code Playgroud)

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

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

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

mik*_*1aj 16

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

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

convmv -f cp1250 -t utf8 -r .
Run Code Online (Sandbox Code Playgroud)

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


slh*_*hck 15

如果您想同时重命名文件目录,将会遇到一些问题。重命名一个文件很容易。但是您要确保目录也被重命名。你不能简单地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
Run Code Online (Sandbox Code Playgroud)

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

将此脚本另存为rename.sh,使用chmod +x rename.sh. 然后,将其称为rename.sh /some/path.

确保解决任何文件名冲突(“ Notice”公告)。

如果您绝对确定它进行了正确的替换,请echo从脚本中删除以实际重命名事物,而不仅仅是打印它的作用。

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


选项说明

解释这里发生的事情:

  • -depth将确保目录递归深度优先,因此我们可以从最后“卷起”所有内容。通常,find遍历方式不同(但不是广度优先)。
  • -print0确保find输出是空分隔的,因此我们可以将其读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
Run Code Online (Sandbox Code Playgroud)

这是在调试模式下运行的输出(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é
Run Code Online (Sandbox Code Playgroud)

注意对于不存在的消息with-hyphen.txtscheduletest本身。