Contents

在Unix中查找重复文件

1. 简介

在本教程中,我们将了解一些在 Unix 系统中查找重复文件的不同方法。

2. 文件结构

首先,让我们快速浏览一下我们将用于示例的文件结构:

.
+--blogdemo
|  +--folder1
|  |  +--text-file-1
|  |  |  Content: "I am not unique"
|  |  +--text-file-2
|  |  |  Content: "Some random content 1"
|  |  +--unique-file-1
|  |  |  Content: "Some unique content 1\nI am a very long line!"
|  +--folder2
|  |  +--text-file-1
|  |  |  Content: "I am not unique"
|  |  +--text-file-2
|  |  |  Content: "Some random content 2"
|  |  +--unique-file-2
|  |  |  Content: "Some unique content 2! \n I am a short line."
|  +--folder3
|  |  +--text-file-1
|  |  |  Content: "I am not unique"
|  |  +--text-file-2
|  |  |  Content: "Some random content 3"
|  |  +--unique-file-3
|  |  |  Content: "Some unique content 3\nI am an extreme long line............"

blogdemo目录将是我们的测试目录。在里面,我们有三个文件夹:folder1folder2folder3。它们中的每一个在每个文件夹中都包含一个具有相同内容的text-file-1文件和一个具有不同内容的text-file-2文件。此外,每个文件夹都包含一个unique-file-x文件,该文件具有唯一的名称和内容。

3. 按名称查找重复文件

查找重复文件的最常用方法是按文件名搜索。我们可以使用脚本来做到这一点:

awk -F'/' '{
  f = $NF
  a[f] = f in a? a[f] RS $0 : $0
  b[f]++ } 
  END{for(x in b)
        if(b[x]>1)
          printf "Duplicate Filename: %s\n%s\n",x,a[x] }' <(find . -type f)

blogdemo目录中运行它应该列出所有具有非唯一名称的文件:

Duplicate Filename: textfile1
./folder3/textfile1
./folder2/textfile1
./folder1/textfile1
Duplicate Filename: textfile2
./folder3/textfile2
./folder2/textfile2
./folder1/textfile2

现在,让我们浏览一下脚本并解释它的作用。

  • *<(find . - type f) -*首先,我们使用进程替换  ,以便awk 命令可以读取find 命令的输出
  • find . -type ffind命令搜索searchPath目录中的所有文件
  • *awk -F’/’ -*我们使用 *’/’*作为 awk命令的FS 。它使提取文件名更容易。最后一个字段将是文件名
  • f = $NF – 我们将文件名保存在变量 f中
  • a[f] = f 在 a? a[f] RS $0 : $0 – 如果关联数组 a[]中不存在文件名,我们创建一个条目以将文件名映射到完整路径。否则,我们添加一个新行RS并将完整路径附加到a[f]
  • b[f]++ – 我们创建另一个数组 *b[]*来记录文件名 f被找到的次数
  • END{for(x in b) – 最后,在END 中,我们遍历数组 b[]中的所有条目
  • if(b >1) - 如果文件名 x被多次看到,即有更多具有此文件名的文件
  • printf “Duplicate Filename: %s\n%s\n”,x,a – 然后我们打印重复的文件名 x,并打印具有此文件名的所有完整路径:  a

请注意,在此示例中,我们仅搜索重复的文件名。在接下来的部分中,我们将发现通过内容查找重复文件的不同方法。

4. 通过MD5校验和查找重复文件

MD5 消息摘要算法是一种广泛使用的散列函数,可根据文件内容生成 128 位散列值。它最初被设计用作加密哈希函数,但它仍然被广泛用作校验和来验证数据完整性。

在 Linux 中,我们可以使用 md5sum 命令来获取文件的 MD5 哈希值。

因为 MD5 是从文件内容生成的,所以我们可以使用它来查找重复文件:

awk '{
  md5=$1
  a[md5]=md5 in a ? a[md5] RS $2 : $2
  b[md5]++ } 
  END{for(x in b)
        if(b[x]>1)
          printf "Duplicate Files (MD5:%s):\n%s\n",x,a[x] }' <(find . -type f -exec md5sum {} +)

正如我们所看到的,它与我们之前通过文件名搜索的非常相似。但是,我们使用添加到find命令的*-exec md5sum {} +*参数为每个文件额外生成一个 MD5 哈希。

让我们在测试目录中运行它并检查输出:

Duplicate Files (MD5:1d65953b527afb4bd9bc0986fd0b9547):
./folder3/textfile1
./folder2/textfile1
./folder1/textfile1

如我们所见,虽然我们有三个名为text-file-2 的文件,但它们不会出现在 MD5 哈希搜索中,因为它们的内容是唯一的。

5. 按大小查找重复文件

当有大量文件要检查时,计算每个文件的哈希可能需要很长时间。在这种情况下,我们可以从查找大小相同的文件开始,然后对它们进行哈希检查。这将加快搜索速度,因为所有重复文件都应具有相同的文件大小。

我们可以使用 du 命令来计算文件的大小。

让我们编写一个脚本来查找相同大小的文件:

awk '{
  size = $1
  a[size]=size in a ? a[size] RS $2 : $2
  b[size]++ } 
  END{for(x in b)
        if(b[x]>1)
          printf "Duplicate Files By Size: %d Bytes\n%s\n",x,a[x] }' <(find . -type f -exec du -b {} +)

在本例中,我们将*-exec du -b {} +参数添加到find命令中,以将每个文件的大小传递给 awk命令。 在blogdemo/*目录中执行它会产生输出:

Duplicate Files By Size: 16 Bytes
./folder3/textfile1
./folder2/textfile1
./folder1/textfile1
Duplicate Files By Size: 22 Bytes
./folder3/textfile2
./folder2/textfile2
./folder1/textfile2

这些结果在内容重复方面是不正确的,因为每个test-file-2都有不同的内容,即使它们具有相同的大小。 但是,我们可以使用此输入在较小的范围内执行其他重复检查。

6. 使用fdupesjdupes查找重复文件

有许多现成的程序结合了许多查找重复文件的方法,例如检查文件大小和 MD5 签名。

一种流行的工具是*fdupes 。*它通过按大小和 MD5 签名比较文件来工作。如果它们相等,则进行逐字节比较。

jdupes 被认为是fdupes的增强分支。在对各种数据集进行测试时,平均而言,jdupes似乎比fdupes快得多。

要使用fdupes搜索重复文件,我们输入:

fdupes -r .

并使用jdupes搜索重复项:

jdupes -r .

这两个命令都将产生相同的输出:

./folder1/text-file-1
./folder2/text-file-1
./folder3/text-file-1

请注意——尽管jdupes与最初派生的 fdupes 非常相似,但jdupes并未开发fdupes 的兼容替代品。