我有一个巨大的歌曲文件夹,结构混乱,文件重复在多个文件夹中。
我需要推荐一个工具或脚本,可以通过简单的两个匹配来查找和删除重复项:
- 完全相同的文件名
- 文件大小完全相同
在这种情况下,和song.mp3
中存储的文件大小为 1234 字节。工具/脚本应仅保留一份副本。/songs/album1
/songs/albumz
我努力了茨考卡在 Fedora 上,但它可以按文件名或文件大小搜索,但不能两个都结合在一起。
答案1
rdfind
可能会执行您想要的操作,但您需要依赖加密哈希/校验和(md5、sha1 或 sha256)来代替文件大小。
哈希值是比文件大小更严格的标准,但这可能是也可能不是您想要的。例如,考虑所有元数据在音乐文件中:如果一个文件被列为Schubert
作曲家,而另一个潜在的重复文件被列为Bruckner
作曲家和文件中的其他所有内容都完全相同文件大小过滤器会将其分类为匹配项,但是哈希过滤器不会。这哈希过滤器将使用比文件大小过滤器,但如果您只是偶尔过滤重复项,那么这可能不是问题。
在实际运行之前rdfind
,请务必man rdfind
仔细阅读并使用该-dryrun
选项,直到您确信结果是您想要的为止。
FWIW,本教程listrdfind
和其他 3 个用于查找重复文件的实用程序。
我不知道有一种可以过滤文件大小的工具,但如果我从头开始创建一个工具,我想我会使用find
和拼凑一些东西awk
。让我们知道这是否是您想要的 - 我认为这并不是非常困难,但如果rdfind
满足您的需求也没有多大意义。
答案2
您确实不需要为此使用外部实用程序。通过链接一组标准命令,您可以走很远的路,通过将它们存储在 shell 脚本或函数中,您可以始终记住它们。
要检测重复项,您可以将所有文件路径存储在关联数组中,以大小加文件名为键。但因为您表明您有一个很大的文件集合,所以我建议改为进行排序。然后第二次排序独特的选项,这样比较两个结果即可得到重复的结果。
您想使用第一次排序的输出两次。我可以为此使用临时文件;对于这个简单的工作,命名管道和 fifo 等并不需要更少的工作。该命令将为您
mktemp
打印目录中安全唯一的文件名。/tmp/
随着命令替换您$(...)
可以将该名称分配给名为的变量tmp
或其他名称。回显它以了解您在做什么。现在您想要使用 2 个关键字段:大小和文件名,并且还需要完整路径。方便的是斜杠
/
不是有效的文件名字符:它保留用于分隔目录名和文件名。因此,您可以使用/
作为这 3 个字段之间的分隔符。-printf
该命令的操作可以find
为您提供:找到所有-type f
(ile),并打印它们的大小%s
、文件名%f
和完整路径%p
,所有内容均以 分隔/
。完整路径将包含更多斜杠,但我们知道只有前 2 个斜杠分隔符(我们在格式中明确指定的斜杠分隔符-printf
)是我们的。|
将命令的输出find
(大小、文件名和完整路径的列表)通过管道传输到sort
命令。告诉它字段由斜杠分隔:-t /
,并且密钥位于前 2 个字段中:-k 1,2
。您可以立即将排序后的列表存储在临时文件中,但我选择让tee
命令执行此操作,因为这样您可以保持一个管道打开,以获得更好的性能。|
将排序后的列表通过管道传输到tee
,它将其副本存储到给定的 filename"$tmp"
,并在某种程度上将管道回显到下一个管道。Pipe
|
tee
将排序后的列表回显到第二个,在相同的键上,但现在在排序键中sort
输出-u
or 。--unique
将
|
唯一大小+文件名条目的列表通过管道传输到diff
命令作为第一个输入-
(标准输入),并使用临时文件"$tmp"
作为第二个。通常diff
会在其输出中添加一些标记,以便您可以识别更改的性质。但我们不需要它,而且它会扰乱我们需要的输出。我们知道唯一列表的每个条目也在完整列表中。我们只想要完整列表中的普通额外行。这就是命令的选项所diff
要求的。到目前为止的命令将输出一个希望简短的具有重复文件的列表。每组重复项中的一个被省略,因为它仍然出现在唯一列表中。为了处理该列表的每个条目,并对其最后一部分(完整路径名)进行操作,我们将
|
其通过管道传输到一个while read
构造中。它将每一行存储在给定的参数名称下dupl
。使用 bash 参数扩展语法,#
我们省略了前缀*/*/
,即大小加上文件名及其斜杠/
分隔符,剩下的是文件副本的完整路径。我建议您首先执行完整的命令echo
,并在彻底检查后将其替换为删除rm
命令,或者更好的是,使用其中一个垃圾桶实用程序将重复项移动到您的Trash
,以便您的目录被清理,但什么也没有丢失了。tmp=$(mktemp) echo temp file is "$tmp" find -type f -printf "%s/%f/%p\n" | sort -t / -k 1,2 | tee "$tmp" | sort -t / -k 1,2 -u | diff --new-line-format="%L" --unchanged-line-format="" - "$tmp" | while read dupl;do echo "${dupl#*/*/}"; done rm "$tmp"
后面收拾一下,把临时文件清理干净
"$tmp"
。
答案3
这是一种无需安装任何其他软件包的快速方法:
#!/bin/bash
find /path/to/compare/against -type f -printf "%s %f\n" | \
while read SIZE FILE; do
find /where/to/look/for/duplicates -iname "$FILE" -size "${SIZE}c" | \
while read DUPLICATE; do
# whatever you want to do with the duplicate file
done
done