是否可以在磁盘上找到完全相同但文件名不同的重复文件?

评论

请注意,执行此操作的任何可能方法都必须将系统上的每个文件与其他文件进行比较。因此,即使使用快捷方式,这也将花费很长时间。

@Shadur如果可以接受校验和,可以归结为仅比较哈希-在大多数系统上,哈希约为10 ^(5 + -1),通常<64字节。当然,您必须至少读取一次数据。 :)

@Shadur这是不正确的。您可以通过以下方法减少时间:检查匹配的st_size,消除那些仅具有相同的st_size,然后仅计算匹配的st_sizes的md5sums。

@Shadur甚至是一种禁止任何哈希操作的愚蠢方法,都可以使用几种排序算法(基于文件内容)在Θ(n log n)比较(而非Θ(n²))中做到这一点。
@ChrisDown是的,尺寸匹配将是我想到的快捷方式之一。

#1 楼

我想添加一个最近的增强型fdupes fork,jdupes,它有望比fdupes更快并且功能更丰富(例如大小过滤器):在当前目录中找到大于50MB的重复文件,并在myjdups.txt中输出结果列表。上面的@Chris_Down答案可实现此目的:

jdupes . -rS -X size-:50m > myjdups.txt


评论


注意:最新版本的jdupes支持仅具有部分哈希的匹配文件,而不必等待对整个对象进行哈希。很有用。 (您必须克隆git存档才能获得它。)这是我现在正在使用的选项:jdupes -r -T -T -T --exclude = size-:50m --nohidden

– SurpriseDog
19年7月3日在17:48

#2 楼

fdupes可以做到这一点。来自man fdupes


在给定路径中搜索重复文件。通过比较文件大小和MD5签名,然后进行逐字节比较,可以找到此类文件。


在Debian或Ubuntu中,可以使用apt-get install fdupes进行安装。在Fedora / Red Hat / CentOS中,可以使用yum install fdupes进行安装。在Arch Linux上,您可以使用pacman -S fdupes,在Gentoo上,可以使用emerge fdupes。 br />
如注释中所述,您可以通过执行以下操作来获得最大的重复项:

评论


谢谢。如何过滤最大的骗子?如何使尺寸易于阅读?

–学生
13年4月5日在9:31

@student:使用类似的东西(确保fdupes仅输出没有多余信息的文件名,或剪切或sed保留它):fdupes ....... | xargs ls -alhd | egrep'M | G'将文件保留为人类可读格式,并且仅保留大小为兆字节或千兆字节的文件。更改命令以适合实际输出。

–奥利维尔·杜拉克(Olivier Dulac)
13-4-5在12:27



@OlivierDulac您永远不要解析ls。通常情况下,这种情况比用例要糟,但是即使在用例中,您也冒着误报的风险。

–克里斯唐(Chris Down)
13年4月5日在13:13

@student-获得文件名后,通过管道将其排序将告诉您。

–克里斯唐(Chris Down)
13年4月5日在13:14

@ChrisDown:的确是个坏习惯,并且会带来误报。但是在那种情况下(交互式使用,并且仅用于显示,没有“ rm”或任何直接依赖它的类型),它很好并且很快速^^。我喜欢您链接到的那些页面,顺便说一句(几个月以来一直在阅读它们,并且充满了许多有用的信息)

–奥利维尔·杜拉克(Olivier Dulac)
13年4月5日在14:05

#3 楼

另一个好的工具是fslint


fslint是一个工具集,用于查找文件系统的各种问题,
包括重复文件和有问题的文件名等。

除了GUI之外,还可以使用单独的命令行工具来访问它们,可以在标准安装中将/ usr / share / fslint / fslint目录更改为或添加到$ PATH中。该目录中的每个命令都有一个
--help选项,可进一步详细说明其参数。

   findup - find DUPlicate files



在基于debian的系统上,您可以使用以下软件进行安装:

sudo apt-get install fslint



如果您不想或无法安装第三方工具,也可以手动执行此操作。大多数此类程序的工作方式是通过计算文件校验和。具有相同md5sum的文件几乎可以肯定包含完全相同的数据。因此,您可以执行以下操作:

find / -type f -exec md5sum {} \; > md5sums
awk '{print }' md5sums | sort | uniq -d > dupes
while read -r d; do echo "---"; grep -- "$d" md5sums | cut -d ' ' -f 2-; done < dupes 


示例输出(此示例中的文件名相同,但不同时也可以使用):

$ while read -r d; do echo "---"; grep -- "$d" md5sums | cut -d ' ' -f 2-; done < dupes 
---
 /usr/src/linux-headers-3.2.0-3-common/include/linux/if_bonding.h
 /usr/src/linux-headers-3.2.0-4-common/include/linux/if_bonding.h
---
 /usr/src/linux-headers-3.2.0-3-common/include/linux/route.h
 /usr/src/linux-headers-3.2.0-4-common/include/linux/route.h
---
 /usr/src/linux-headers-3.2.0-3-common/include/drm/Kbuild
 /usr/src/linux-headers-3.2.0-4-common/include/drm/Kbuild
---


这将比已经提到的专用工具要慢得多,但是可以使用。

评论


使用st_size查找具有与另一个文件相同大小的任何文件,消除只有一个具有该大小的文件的文件,然后仅在具有相同st_size的文件之间计算md5sums,会快得多。

–克里斯唐(Chris Down)
13-4-4在16:34



@ChrisDown是的,只是想保持简单。您的建议当然会大大加快速度。这就是为什么我在回答结束时对它的运行缓慢表示免责。

– terdon♦
13年4月4日在16:37

它可以在macOS上运行,但是您应将md5sum {}替换为md5 -q {},并将gawk'{print $ 1}'替换为cat

– Finesse
19-10-24在2:26

#4 楼

简短的答案:是的。

较长的版本:看看Wikipedia fdupes条目,它提供了很多不错的现成解决方案。当然,您可以编写自己的代码,并不是那么困难-像diffsha*sumfindsortuniq这样的哈希程序就可以完成任务。您甚至可以将其放在一行上,并且仍然可以理解。

#5 楼

如果您认为您的域上的哈希函数(此处为MD5)是无冲突的:

find $target -type f -exec md5sum '{}' + | sort | uniq --all-repeated --check-chars=32 \
 | cut --characters=35-


是否要将相同的文件名分组?编写一个简单的脚本not_uniq.sh以格式化输出:

#!/bin/bash

last_checksum=0
while read line; do
    checksum=${line:0:32}
    filename=${line:34}
    if [ $checksum == $last_checksum ]; then
        if [ ${last_filename:-0} != '0' ]; then
            echo $last_filename
            unset last_filename
        fi
        echo $filename
    else
        if [ ${last_filename:-0} == '0' ]; then
            echo "======="
        fi
        last_filename=$filename
    fi

    last_checksum=$checksum
done


,然后更改find命令以使用您的脚本: />这是基本思路。如果文件名包含一些字符,则可能应该更改find。 (例如空格)

#6 楼

Wikipedia上有一篇文章(http://en.wikipedia.org/wiki/List_of_duplicate_file_finders),其中包含用于此任务的可用开源软件列表,但现在已删除。

我将添加该内容GUI版本的fslint非常有趣,允许使用掩码选择要删除的文件。在清除重复的照片时非常有用。 linux)我没有检查FSLint

评论


最好在此处提供实际信息,而不仅仅是链接,链接可能会更改,然后答案就没有价值了

–安东
2014年1月29日,11:22

维基百科页面为空。

– ihor_dvoretskyi
2015年9月10日上午9:01

是的,它已经被清洗了,真可惜……

–MordicusEtCubitus
15年12月21日在16:23

我用这3个工具编辑了它

–MordicusEtCubitus
15年12月21日在16:30

#7 楼

我遇到的情况是我无法安装新软件,因此不得不扫描> 380 GB的JPG和MOV文件进行重复。我开发了以下POSIX awk脚本,以在72秒内处理所有数据(与find -exec md5sum方法相反,该方法需要花费90多分钟才能运行):
/master/unix_utils/find-dupes.awk
您可以这样称呼:
ls -lTR | awk -f find-dupes.awk
它是在FreeBSD Shell环境中开发的,因此可能需要一些调整才能在GNU / Linux Shell环境。

#8 楼

这是我的看法:

find -type f -size +3M -print0 | while IFS= read -r -d '' i; do
  echo -n '.'
  if grep -q "$i" md5-partial.txt; then echo -e "\n$i  ---- Already counted, skipping."; continue; fi
  MD5=`dd bs=1M count=1 if="$i" status=noxfer | md5sum`
  MD5=`echo $MD5 | cut -d' ' -f1`
  if grep "$MD5" md5-partial.txt; then echo "\n$i  ----   Possible duplicate"; fi
  echo $MD5 $i >> md5-partial.txt
done


不同之处在于,它仅哈希到文件的前1 MB。
有几个问题/功能:


前1 MB后可能会有所不同,因此结果是值得检查的候选对象。我可能以后再解决。
先按文件大小检查可以加快速度。
仅接收大于3 MB的文件。

我用它来比较视频剪辑,所以这是对我来说足够了。

#9 楼

我知道这是坏事,但高度相关。我问过一个类似的问题,即根据文件名的前几个字符查找重复文件,并且提出的解决方案是使用一些awk脚本的解决方案。
我将其用于mod冲突清除,在Forge包1.14.4中很有用+因为Forge现在禁用了较旧的mod,而不是致命的崩溃,并让您知道重复的

 #!/bin/bash

declare -a names

xIFS="${IFS}"
IFS="^M"

while true; do
awk -F'[-_ ]' '
    NR==FNR {seen[tolower()]++; next}
    seen[tolower()] > 1
' <(printf "%s\n" *.jar) <(printf "%s\n" *.jar) > tmp.dat

        IDX=0
        names=()


        readarray names < tmp.dat

        size=${#names[@]}

        clear
        printf '\nPossible Dupes\n'

        for (( i=0; i<${size}; i++)); do
                printf '%s\t%s' ${i} ${names[i]}
        done

        printf '\nWhich dupe would you like to delete?\nEnter # to delete or q to quit\n'
        read n

        if [ $n == 'q' ]; then
                exit
        fi

        if [ $n -lt 0 ] || [ $n -gt $size ]; then
                read -p "Invalid Option: present [ENTER] to try again" dummyvar
                continue
        fi

        #clean the carriage return \n from the name
        IFS='^M'
        read -ra TARGET <<< "${names[$n]}"
        unset IFS

        #now remove the first element from the filesystem
        rm "${TARGET[0]}" 
        echo "removed ${TARGET[0]}" >> rm.log
done

IFS="${xIFS}"
 

我建议保存将其作为“ dupes.sh”发送到您的个人bin或/ usr / var / bin