有没有一种简单的方法可以用硬链接替换重复的文件?


136

我正在寻找一种简单的方法(一个命令或一系列命令,可能涉及find)来找到两个目录中的重复文件,并将一个目录中的文件替换为另一目录中的文件的硬链接。

情况如下:这是一个文件服务器,多个人在上面存储音频文件,每个用户都有自己的文件夹。有时,多个人拥有完全相同的音频文件的副本。现在,这些是重复的。我想使其成为硬链接,以节省硬盘空间。


20
硬链接可能会遇到的一个问题是,如果有人决定对其硬链接的音乐文件之一做某事,他们可能会无意中影响其他人对其音乐的访问。
史蒂文D

4
另一个问题是,即使从同一来源使用相同编码器获取的包含“ Some Really Great Tune”的两个不同文件也极有可能不是逐位相同的。
msw

3
更好的解决方法可能是拥有一个公共音乐文件夹...
Stefan 2010年


1
@tante:使用符号链接不会解决任何问题。当用户“删除”文件时,指向该文件的链接数会减少,而当计数达到零时,文件实际上会被删除,仅此而已。因此删除对于硬链接的文件来说没有问题,唯一的问题是用户试图编辑文件(实际上不太可能)或覆盖文件(如果已登录,则很有可能)。
maaartinus 2012年

Answers:


41

http://cpansearch.perl.org/src/ANDK/Perl-Repository-APC-2.002/eg/trimtrees.pl中有一个perl脚本,它可以完全满足您的要求:

遍历在命令行上命名的所有目录,计算MD5校验和并查找具有相同MD5的文件。如果它们相等,则进行比较,如果确实相等,则用指向第一个的硬链接替换两个文件中的第二个。


听起来很完美,谢谢!我将尝试并接受它是否如描述的那样起作用!
乔什(Josh)

3
这完全符合我的要求。但是,我相信使用dedup的ZFS最终将成为解决问题的方法,因为我确实发现文件之间存在细微差异,因此只有少数文件可以进行硬链接。
乔什2010年

11
对此表示支持,但是在进行了更多研究之后,我还是没有这样做。rdfind可通过所有主要平台(os x,linux,(cyg)win,solaris)的软件包管理器使用,并且以惊人的本机速度工作。因此,请查看下面的答案。
oligofren 2015年

@oligofren我一直在想,但是后来我打了[Errno 31] Too many links。这似乎是唯一可以解决的问题。
phunehehe

5
对每个文件(而不是仅存在至少一个大小相同的其他文件)进行校验和处理,会造成不必要的效率低下(并不必要导致哈希冲突)。
查尔斯·达菲

85

rdfind确实满足您的要求(并且按约翰尼为什么列出的顺序)。使删除重复项成为可能,并用软链接或硬链接替换它们。与symlinks您结合使用还可以使符号链接成为绝对链接或相对链接。您甚至可以选择校验和算法(md5或sha1)。

由于它是经过编译的,因此它比大多数脚本解决方案要快:time在15 GiB文件夹中,2009年我的Mac Mini上有2600个文件,返回

9.99s user 3.61s system 66% cpu 20.543 total

(使用md5)。

在大多数程序包处理程序中可用(例如,用于Mac OS X的MacPorts)。


11
+1我曾经使用过rdfind并且喜欢它。它具有一个-dryrun true选项,可以让您知道它会做什么。使用硬链接替换重复项非常简单-makehardlinks true。它产生了一个不错的日志,它让我知道释放了多少空间。另外,根据作者的基准,rdfind比duff和fslint快。
Daniel Trebbien 2013年

哦,很好。我曾经使用过fdupes,但是在最新的Ubuntu 14.10中缺少用于硬连接dupes的-L选项。速度非常慢,并且在OSX上对于Homebrew不存在,因此这个答案要好得多。谢谢!
oligofren 2015年

非常聪明和快速的算法。
ndemou,2015年

2
我怀疑该工具的性能与算法本身有关,而与它是编译工具还是脚本无关。对于这种操作,磁盘几乎一直都是瓶颈。只要脚本化工具确保在对CPU进行校验和刻录时正在进行异步I / O操作,它们的性能应与本机二进制文件差不多。
cdhowie

rdfind非常依赖于新的操作系统和编译器。(如果未完全重建开发工具,则无法在CentOS 6.x上运行)
Cosmo F

49

使用fdupes工具:

fdupes -r /path/to/folder为您提供目录中重复项的列表(-r使其递归)。输出看起来像这样:


文件
名1 文件名2

filename3
filename4
filename5


其中filename1和filename2相同,并且filename3,filename4和filename5也相同。


1
Ubuntu注意:截至2013年9月,它尚未发布稳定版本(版本为1.50-PR2-3),因此该更新尚未出现在ubuntu中。
斯图尔特·阿克森

11
我只是尝试在Ubuntu和Debian上都安装fdupes_1.50-PR2-4,它们都没有-L标志。幸运的是,从github.com/tobiasschulz/fdupes进行构建非常容易。
neu242

3
尝试rdfindfdupes,但速度更快,并且在OS X和Cygwin上也可用。
oligofren 2015年

6
fdupes似乎只能找到重复项,而不能用硬链接代替它们,因此不能解决IMO问题。
Calimo

2
有一个类似jdupes的基于的工具fdupes,但是它也可以用symlinks(-l),hardlinks(-L)替换重复的文件,或指示btrfs在文件系统级别(-B如果使用btrfs的话)对数据块进行重复数据删除。
Marius Gedminas

23

1
很好的提示,我使用的是常规的基本code.google.com/p/hardlinkpy,但一段时间未更新...
meduz 2012年

2
这似乎与hardlinkFedora / RHEL / etc上的原始版本相似。

1
hardlink现在是许多Linux软件包系统中的本机二进制文件(自2014年以来),而且速度非常快。对于1,2M个文件(320 GB),只用了200秒(链接了大约10%的文件)。
Marcel Waldvogel's

FWIW,以上内容hardlink由Julian Andres Klode创建,而Fedora hardlink由Jakub Jelinek创建(来源:pagure.io/hardlink-Fedora软件包名称:hardlink)
maxschlepzig

18

这是由“fslint”所提供的功能之一- http://en.flossmanuals.net/FSlint/Introduction

点击“合并”按钮:

屏幕截图


4
-m将硬链接复制在一起,-d将删除除一个以外的所有副本,-t将

1
在Ubuntu上,该怎么做:(sudo apt-get install fslint /usr/share/fslint/fslint/findup -m /your/directory/tree默认情况下,目录/ usr / share / fslint / fslint /不在$ PATH中)
Jocelyn

14

由于您的主要目标是节省磁盘空间,因此还有另一种解决方案:在文件系统级别进行重复数据删除(可能还进行压缩)。与硬链接解决方案相比,它不存在无意影响其他链接文件的问题。

自从池版本23起,ZFS就已经降级(块级,而不是文件级),并且很久以前就进行了压缩。如果您使用的是Linux,则可以尝试zfs-fuse,或者如果您使用的是BSD,则本机支持。


这可能是我最终要采用的方法,但是BSD的ZFS实现是否可以简化?我以为没有。
乔什2010年

此外,DragonFlyBSD上的HAMMER文件系统具有重复数据删除支持。
hhaamu'7

14
ZFS dedup是没有人的朋友。ZFS建议每1Tb可用磁盘空间使用1Gb内存的地方,如果您尝试使用每1Tb可用磁盘空间使用少于32Gb ram的dedup的话,您会大为恼火。这意味着对于1Tb镜像,如果您没有32 Gb的ram,则很可能迟早会遇到内存炸弹的情况,由于缺少ram,这将使机器停止运行。到那里去了,做到了,仍然从PTSD中恢复过来。
killermist 2014年

4
为避免在线重复数据删除(即检查每次写入)对RAM的过多要求,请btrfs使用批处理离线重复数据删除(在您认为有用/必要时运行它) btrfs.wiki.kernel.org/index.php/Deduplication
Marcel Waldvogel

3
七年后的更新:我最终确实迁移到ZFS并尝试了重复数据删除-我发现它的RAM需求确实确实很高。巧妙使用ZFS快照提供了我最终使用的解决方案。(复制一个用户的音乐,快照和克隆,并使用rsync --inplace存储的第二个用户的音乐复制到克隆中,这样就只存储更改的块)
Josh


5

要查找重复文件,可以使用duff

Duff是Unix命令行实用程序,用于快速查找给定文件集中的重复项。

只需运行:

duff -r target-folder

要自动创建到这些文件的硬链接,您将需要使用bash或其他某种脚本语言来解析duff的输出。


不过速度确实很慢-参见rdfind.pauldreik.se/#g0.6
ndemou

5
aptitude show hardlink

说明:硬链接相同文件的多个副本硬链接是一种检测同一文件的多个副本并将其替换为硬链接的工具。

这个想法来自http://code.google.com/p/hardlinkpy/,但是代码是从头开始编写的,并根据MIT许可获得了许可。主页:http : //jak-linux.org/projects/hardlink/


这里提到的唯一可用于Gentoo的程序,无需取消屏蔽即可使用,并具有硬链接支持,谢谢!
Jorrit Schippers 2015年

4

我已经使用了这里提到的许多用于Linux的硬链接工具。我在Ubuntu上也被ext4 fs所困扰,并且一直在使用它的cp -l-s进行硬/软链接。但是最近在cp手册页中注意到了轻量级副本,这意味着在修改一侧之前要保留冗余磁盘空间:

   --reflink[=WHEN]
          control clone/CoW copies. See below

       When  --reflink[=always]  is specified, perform a lightweight copy, where the 
data blocks are copied only when modified.  If this is not possible the
       copy fails, or if --reflink=auto is specified, fall back to a standard copy.

我想我将更新cp别名以--reflink=auto现在始终包含参数
Marcos 2012年

1
ext4真的支持--reflink吗?

7
btrfs和OCFS2支持此功能。只能在写时复制文件系统上使用,而ext4则不能。btrfs确实正在形成。我喜欢使用它,因为它具有reflink和快照功能,使您不必担心对大文件树进行大规模操作。
clacke 2012年

3

在我看来,首先检查文件名可以加快处理速度。如果两个文件缺少相同的文件名,那么在很多情况下,我不会认为它们是重复的。似乎最快的方法是按顺序进行比较:

  • 文档名称
  • 尺寸
  • md5校验和
  • 字节内容

请问有什么方法吗?看看dufffdupesrmlintfslint,等。

以下方法是在commandlinefu.com上投票最多的:查找重复文件(首先基于大小,然后基于MD5哈希)。

第一步可以添加文件名比较,第二步可以添加文件大小比较吗?

find -not -empty -type f -printf "%s\n" | sort -rn | uniq -d | \
  xargs -I{} -n1 find -type f -size {}c -print0 | xargs -0 md5sum | \
  sort | uniq -w32 --all-repeated=separate

3
我已经用过dufffdupes并且rmlint强烈建议读者阅读其中的第三条。它具有出色的选项集(和文档)。有了它,我可以避免很多我需要与其他工具一起使用的后期处理。
dubiousjim

3
在我的实践中,文件名是最可靠的因素,我已将其从重复数据删除的所有工作中完全删除。install.sh在活动的系统上可以找到多少个文件?我无法计算保存文件并发生名称冲突的次数,并且需要进行一些动态重命名来保存它。反面:不知道我在不同的日子从不同的来源下载了多少次,却发现它们是同一个文件,但名称不同。(这也破坏了时间戳的可靠性。)1:大小,2:摘要,3:字节内容。
Gypsy Spellweaver

@GypsySpellweaver:(1)取决于个人用例,您不同意吗?就我而言,我有多个备份的多个还原,其中具有相同名称和内容的文件存在于不同的还原文件夹中。(2)您的评论似乎假设比较文件名。我并不是在建议取消其他检查。
约翰尼,为什么

2

由于我不喜欢Perl,因此这里是bash版本:

#!/bin/bash

DIR="/path/to/big/files"

find $DIR -type f -exec md5sum {} \; | sort > /tmp/sums-sorted.txt

OLDSUM=""
IFS=$'\n'
for i in `cat /tmp/sums-sorted.txt`; do
 NEWSUM=`echo "$i" | sed 's/ .*//'`
 NEWFILE=`echo "$i" | sed 's/^[^ ]* *//'`
 if [ "$OLDSUM" == "$NEWSUM" ]; then
  echo ln -f "$OLDFILE" "$NEWFILE"
 else
  OLDSUM="$NEWSUM"
  OLDFILE="$NEWFILE"
 fi
done

这将查找具有相同校验和的所有文件(无论它们是大,小还是已经进行了硬链接),并将它们硬链接在一起。

对于重复运行,可以使用其他查找标志(例如大小)和文件缓存(因此您不必每次都重做校验和)进行极大地优化。如果有人对更智能,更长的版本感兴趣,可以将其发布。

注:如前所述,只要文件不需要修改或在文件系统之间移动,硬链接就可以工作。


我该如何更改脚本,而不是对其进行硬链接,它只会删除重复的文件,并将已删除文件->内衬文件添加到CSV文件中。。???
MR.GEWA,

当然。硬链接行:echo ln -f“ $ OLDFILE”“ $ NEWFILE”只需用硬链接替换重复的文件,因此您可以通过$ NEWFILE更改它。
seren

以及如何在下一行中以某种方式写一些文本文件$ OLDFILE-> NEWFILE ???
MR.GEWA,2013年

啊,对。是的,添加一行的RM如后:回声“$ NEWFILE” >> /var/log/deleted_duplicate_files.log
SEREN

2
不要花钱重新发明轮子。有可用的,比如更加成熟的解决方案rdfind,即工作在本地的速度,只是要求brew install rdfindapt-get install rdfind得到安装。
oligofren 2015年

1

我制作了一个Perl脚本,它执行的操作与您所谈论的相似:

http://pastebin.com/U7mFHZU7

基本上,它只是遍历目录,计算其中的文件的SHA1sum,将其哈希化并将匹配链接在一起。它在许多场合都派上用场。


2
我希望尽快解决这个问题...为什么不将其上传到CPAN ... App :: relink或其他内容
xenoterracide

2
@xenoterracide:因为已经存在所有类似且更成熟的解决方案。查看其他答案,尤其是rdfind。
oligofren 2015年

1
我毫不怀疑存在更好的解决方案。我猜是TMTOWTDI。
amphetamachine



1

jdupes 已在评论中提及,但应有自己的答案,因为它可能在大多数发行版中都可用并且运行非常快(它仅在大约一分钟的时间内释放了2.7 GB的158 GB完整分区(SSD驱动器)中的2.7 GB):

jdupes -rL /foo/bar

0

如果要进行硬链接,请注意该文件的权限。注意,所有者,组,模式,扩展属性,时间和ACL(如果使用的话)存储在INODE中。只有文件名不同,因为文件名存储在目录结构中,其他指向INODE属性。因此,链接到同一索引节点的所有文件名都具有相同的访问权限。您应该防止修改该文件,因为任何用户都可能将文件损坏。很简单。足够了,任何用户都可以使用相同的名称放置其他文件。然后保存索引节点号,并为所有硬链接名称破坏(替换)原始文件内容。

更好的方法是在文件系统层上进行重复数据删除。您可以使用BTRFS(上次非常流行),OCFS或类似方法。查看页面:https ://zh.wikipedia.org/wiki/Comparison_of_file_systems,特别是在表功能和列重复数据删除中。您可以单击它并进行排序:)

特别看看ZFS文件系统。这可以作为FUSE使用,但这种方式非常慢。如果需要本机支持,请查看页面http://zfsonlinux.org/。然后,您必须修补内核,然后安装用于管理的zfs工具。我不明白,为什么Linux不支持作为驱动程序,这是许多其他操作系统/内核的方法。

文件系统通过两种方式支持重复数据删除,即重复数据删除或块删除。ZFS支持块。这意味着,可以删除在同一文件中重复的相同内容。其他方法是对数据进行重复数据删除的时间,该时间可以是联机(zfs)或脱机(btrfs)。

注意,重复数据删除会消耗RAM。这就是为什么将文件写入通过FUSE挂载的ZFS卷会导致性能显着降低的原因。文档中对此进行了描述。但是您可以在线设置卷上的开/关重复数据删除功能。如果看到任何数据应进行重复数据删除,则只需将重复数据删除设置为开,将某些文件重写为任何临时文件,最后替换。之后,您可以关闭重复数据删除并恢复完整性能。当然,您可以将任何缓存磁盘添加到存储中。这可以是非常快速的旋转磁盘或SSD磁盘。当然这可以是很小的磁盘。在实际工作中,这是替换RAM的方法:)

在Linux下,您应该注意ZFS,因为并非所有功能都能正常工作,特别是在管理文件系统,制作快照等时,但是如果您进行配置而不更改它,则所有功能都可以正常工作。换句话说,您应该将linux更改为opensolaris,它本机支持ZFS :) ZFS的优点是,它既可以用作文件系统,又可以用作类似于LVM的volumen Manager。使用ZFS时不需要它。如果您想了解更多信息,请参阅文档。

注意ZFS和BTRFS之间的区别。ZFS更老,更成熟,不幸的是仅在Solaris和OpenSolaris下(不幸的是被oracle扼杀)。BTRFS较年轻,但上次获得了很好的支持。我建议使用新内核。ZFS具有在线重复数据删除功能,这会导致写入速度变慢,因为所有内容都是在线计算的。BTRFS支持离线重复数据删除。这样可以节省性能,但是当主机无关时,您可以定期运行用于重复数据删除的工具。BTRFS是在linux下本地创建的。也许这对您来说是更好的FS :)


1
我确实喜欢离线(或批处理)重复数据删除方法btrfs。有关选项(包括cp --reflink选项)的出色讨论,位于:btrfs.wiki.kernel.org/index.php/Deduplication
Marcel Waldvogel,2017年

ZFS不仅是Solaris或OpenSolaris。FreeBSD本身支持它。另外,Linux 上的 ZFS 也是基于设备驱动程序的。FUSE上的ZFS是另一回事。
KJ Seefried

0

硬链接可能不是最好的主意。如果一个用户更改了文件,则会同时影响两个文件。但是,删除硬链接不会同时删除两个文件。另外,我不能完全确定硬链接是否占用与同一文件的多个副本相同的空间(在硬盘上,而不是操作系统上)。根据Windows(带有Link Shell扩展),它们确实可以。当然,那是Windows,而不是Unix ...

我的解决方案是在一个隐藏的文件夹中创建一个“公用”文件,并用符号链接替换实际的重复项...然后,符号链接将嵌入元数据或备用文件流,该文件流仅记录两个“文件”彼此不同,例如,如果一个人想要更改文件名或添加自定义专辑封面或类似内容;它甚至可能在数据库应用程序之外很有用,例如安装同一游戏或软件的多个版本,并以最小的差异独立测试它们。


0

最简单的方法是使用特殊程序dupeGuru

dupeGuru首选项截图

作为文档

删除选项

这些选项影响重复删除的发生方式。大多数时候,您不需要启用任何一个。

链接已删除的文件:

删除的文件将替换为指向参考文件的链接。您可以选择用符号链接或硬链接替换它。...符号链接是文件路径的快捷方式。如果原始文件被删除或移动,则链接断开。硬链接是指向文件本身的链接。该链接与“真实”文件一样好。仅当删除到文件的所有硬链接时,文件本身才会被删除。

在OSX和Linux上,完全支持此功能,但是在Windows下,它有点复杂。Windows XP不支持它,但是Vista和更高版本支持它。但是,要使该功能正常运行,dupeGuru必须以管理特权运行。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.