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 脚本来处理所有这些应该不难创建,但我不够专业,无法找出如何自己编写它。
第一的; 您需要使用符号链接而不是通常的硬链接是否有原因?我很难理解具有相对路径的符号链接的必要性。这是我解决这个问题的方法:
我认为 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)
现在,这些文件都具有相同的索引节点号,这意味着它们都指向磁盘上相同的物理数据。
我希望这能解决您的问题,或者至少为您指明正确的方向!
我有类似的情况,但在我的情况下,符号链接应该指向一个相对路径,所以我写了这个 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)
对于每个输入行(它是一个文件列表),脚本拆分文件列表(空格分隔),获取从每个文件到第一个文件的相对路径,然后创建符号链接。