查找重复文件并用符号链接替换它们

Sek*_*mty 19 symlink fdupes duplicate-files

我试图找到一种方法来检查给定目录中的重复文件(即使名称不同),并将它们替换为指向第一次出现的符号链接。我试过,fdupes但它只列出了那些重复项。
这就是上下文:我正在根据自己的喜好自定义图标主题,我发现许多图标,即使它们在父文件夹中具有不同的名称和不同的位置,并且用于不同的目的,基本上都是相同的图片。由于在真正需要一个图像时应用相同的修改二十或三十次是多余的,我只想保留一个图像并符号链接所有其他图像。

例如,如果我fdupes -r ./在目录中运行testdir,它可能会返回以下结果:

./file1.png
./file2.png
./subdir1/anotherfile.png
./subdir1/subdir2/yetanotherfile.png
Run Code Online (Sandbox Code Playgroud)

鉴于此输出,我想只保留 file file1.png,删除所有其他文件并用指向它的符号链接替换它们,同时保留所有原始文件名。所以file2.png会保留它的名字,但会变成一个链接file1.png而不是重复。

这些链接不应指向绝对路径,而应相对于父testdir目录;即yetanotherfile.png会点../../file1.png,不/home/testuser/.icons/testdir/file1.png

我对涉及 GUI 和 CLI 的解决方案都感兴趣。fdupes我已经引用了它不是强制性的,因为它是我知道的一种工具,但我对使用其他工具的解决方案也持开放态度。

我很确定一个 bash 脚本来处理所有这些应该不难创建,但我不够专业,无法找出如何自己编写它。

And*_*nce 9

如果您不喜欢太多脚本,那么我可以推荐rdfind。这将扫描给定目录中的重复文件并用硬链接或符号链接替换它们。我用它来对我的 Ruby gems 目录进行重复数据删除并取得了巨大成功。它在 Debian/Ubuntu 中可用。

  • rdfind +1。`rdfind -makesymlinks true /path/` (4认同)

arn*_*efm 5

第一的; 您需要使用符号链接而不是通常的硬链接是否有原因?我很难理解具有相对路径的符号链接的必要性。这是我解决这个问题的方法:

我认为 Debian (Ubuntu) 版本的 fdupes 可以使用该-L选项用硬链接替换重复项,但我没有 Debian 安装来验证这一点。

如果您没有带有该-L选项的版本,您可以使用我在commandlinefu上找到的这个小 bash 脚本。
请注意,此语法仅适用于 bash。

fdupes -r -1 path | while read line; do master=""; for file in ${line[*]}; do if [ "x${master}" == "x" ]; then master=$file; else ln -f "${master}" "${file}"; fi; done; done
Run Code Online (Sandbox Code Playgroud)

上面的命令将找到“path”中的所有重复文件,并将它们替换为硬链接。您可以通过运行ls -ilR并查看索引节点号来验证这一点。这是包含十个相同文件的示例:

$ ls -ilR

total 20
3094308 -rw------- 1 username group  5 Sep 14 17:21 file
3094311 -rw------- 1 username group  5 Sep 14 17:21 file2
3094312 -rw------- 1 username group  5 Sep 14 17:21 file3
3094313 -rw------- 1 username group  5 Sep 14 17:21 file4
3094314 -rw------- 1 username group  5 Sep 14 17:21 file5
3094315 drwx------ 1 username group 48 Sep 14 17:22 subdirectory

./subdirectory:
total 20
3094316 -rw------- 1 username group 5 Sep 14 17:22 file
3094332 -rw------- 1 username group 5 Sep 14 17:22 file2
3094345 -rw------- 1 username group 5 Sep 14 17:22 file3
3094346 -rw------- 1 username group 5 Sep 14 17:22 file4
3094347 -rw------- 1 username group 5 Sep 14 17:22 file5
Run Code Online (Sandbox Code Playgroud)

所有文件都有单独的索引节点号,使它们成为单独的文件。现在让我们对它们进行重复数据删除:

$ fdupes -r -1 . | while read line; do j="0"; for file in ${line[*]}; do if [ "$j" == "0" ]; then j="1"; else ln -f ${line// .*/} $file; fi; done; done
$ ls -ilR
.:
total 20
3094308 -rw------- 10 username group  5 Sep 14 17:21 file
3094308 -rw------- 10 username group  5 Sep 14 17:21 file2
3094308 -rw------- 10 username group  5 Sep 14 17:21 file3
3094308 -rw------- 10 username group  5 Sep 14 17:21 file4
3094308 -rw------- 10 username group  5 Sep 14 17:21 file5
3094315 drwx------  1 username group 48 Sep 14 17:24 subdirectory

./subdirectory:
total 20
3094308 -rw------- 10 username group 5 Sep 14 17:21 file
3094308 -rw------- 10 username group 5 Sep 14 17:21 file2
3094308 -rw------- 10 username group 5 Sep 14 17:21 file3
3094308 -rw------- 10 username group 5 Sep 14 17:21 file4
3094308 -rw------- 10 username group 5 Sep 14 17:21 file5
Run Code Online (Sandbox Code Playgroud)

现在,这些文件都具有相同的索引节点号,这意味着它们都指向磁盘上相同的物理数据。

我希望这能解决您的问题,或者至少为您指明正确的方向!

  • 我在 https://github.com/jbruchon/jdupes 的分支 `jdupes` 具有 `-L` 选项,可以对重复集进行所需的硬链接。 (3认同)
  • 如果我们使用“rsync”到不同类型的文件系统,我们是否需要相对软链接?或者,如果文件系统不保留层次结构,例如,它是一个备份服务器,将所有内容都放在“/《机器名称》/...”下?或者如果您想从备份恢复?我看不出这里将如何保留硬链接。我可能认为,相对的软链接有更好的生存机会。 (3认同)

fil*_*enf 5

我有类似的情况,但在我的情况下,符号链接应该指向一个相对路径,所以我写了这个 python 脚本来解决这个问题:

#!/usr/bin/env python
# Reads fdupes(-r -1) output and create relative symbolic links for each duplicate
# usage: fdupes -r1 . | ./lndupes.py

import os
from os.path import dirname, relpath, basename, join
import sys

lines = sys.stdin.readlines()

for line in lines:
    files = line.strip().split(' ')
    first = files[0]
    print "First: %s "% first
    for dup in files[1:]:
        rel = os.path.relpath(dirname(first), dirname(dup))
        print "Linking duplicate: %s to %s" % (dup, join(rel,basename(first)))
        os.unlink(dup)
        os.symlink(join(rel,basename(first)), dup)
Run Code Online (Sandbox Code Playgroud)

对于每个输入行(它是一个文件列表),脚本拆分文件列表(空格分隔),获取从每个文件到第一个文件的相对路径,然后创建符号链接。