我有一台 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
步骤完成:
mv Motörhead/Encöding Motörhead/Encoding
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。
采用这种方法,只要文件可读且完整,您的收藏集的名称有多混乱/糟糕就并不重要。
(我有没有说过它是免费的?既指言论自由,又指免费啤酒?软件和数据库都是免费的?)