在不同的目录中查找具有相同名称的文件并计算重复项

时间:2012-11-20 16:55:12

标签: linux algorithm bash

我希望你能解决以下问题。我有24个目录,每个目录包含许多(1000)的文件。我想找出哪个目录组合包含最多的重复(仅限名称)文件。例如,如果我们只考虑4个目录

dir1 dir2 dir3 dir4

包含以下目录内容

dir1

  

1.fa 2.fa 3.fa 4.fa 5.fa

dir2

  

1.fa 10.fa 15.fa

dir3

  

1.fa 2.fa 3.fa

dir4

  

1.fa 2.fa 3.fa 5.fa 8.fa 10.fa

因此,目录dir1和dir4的组合包含最多的重复文件(4)。

24个目录的问题变得非常大,所以我想我可能会使用强力方法。

的内容
  1. 计算所有24个目录中出现的所有重复文件
  2. 删除目录并计算重复文件的数量
  3. 替换目录并删除另一个目录,然后计算数字
  4. 重复所有目录
  5. 获取23个目录的子集,其中包含最多重复文件数
  6. 重复上述2-5并保留22个目录中最多的重复文件
  7. 重复,直到只剩下2个目录
  8. 选择具有最大重复文件数的目录组合
  9. 如果有人有办法这样做,我会非常感谢你提出一些建议。我想过使用fdupesdiff,但无法弄清楚如何解析输出和总结。

5 个答案:

答案 0 :(得分:3)

我用algorithm标记了您的问题,因为我不知道任何现有的bash / linux工具可以帮助您直接解决此问题。最简单的方法是使用Python,C ++或Java等编程语言为此构造算法,而不是使用bash shell。

话虽如此,这里是对你的问题的高层次分析:乍一看它看起来像一个最小集合覆盖问题,但它实际上分为两部分:


第1部分 - 要涵盖的文件集是什么?

您希望找到涵盖最多重复文件的目录组合。但首先,您需要知道24个目录中最大的重复文件集。

由于2个目录之间的文件交集始终大于或等于与第3个目录的交集,因此您将遍历所有目录对并找到最大交集集:

(24 choose 2) = 276 comparisons

您获取找到的最大交集,并将其用作您实际尝试覆盖的集合。


第2部分 - 最小集合覆盖问题

这是well-studied problem in computer science,因此您最好从the writings of people much smarter than I阅读。

我唯一需要注意的是它是NP-Complete problem,所以它并非无足轻重。


这是我能够做到的最好的解决你问题的原始表述的方法,但我觉得这对你真正需要完成的事情来说太过分了。您应该考虑使用您需要解决的实际问题来更新您的问题。

答案 1 :(得分:0)

在shell中计算重复的文件名:

#! /bin/sh

# directories to test for
dirs='dir1 dir2 dir3 dir4'

# directory pairs already seen
seen=''

for d1 in $dirs; do
    for d2 in $dirs; do
        if echo $seen | grep -q -e " $d1:$d2;" -e " $d2:$d1;"; then
            : # don't count twice
        elif test $d1 != $d2; then
            # remember pair of directories
            seen="$seen $d1:$d2;"
            # count duplicates
            ndups=`ls $d1 $d2 | sort | uniq -c | awk '$1 > 1' | wc -l`
            echo "$d1:$d2 $ndups"
        fi
    done
# sort decreasing and take the first
done | sort -k 2rn | head -1

答案 2 :(得分:0)

./ count_dups.sh:

1 files are duplicated Comparing dir1 to dir2.
3 files are duplicated Comparing dir1 to dir3.
4 files are duplicated Comparing dir1 to dir4.
1 files are duplicated Comparing dir2 to dir3.
2 files are duplicated Comparing dir2 to dir4.
3 files are duplicated Comparing dir3 to dir4.

./ count_dups.sh | sort -n |尾巴-1

4 files are duplicated Comparing dir1 to dir4.

使用脚本count_dups.sh:

#!/bin/bash

# This assumes (among other things) that the dirs don't have spaces in the names

cd testdirs
declare -a DIRS=(`ls`);

function count_dups {
    DUPS=`ls $1 $2 | sort | uniq -d | wc -l`
    echo "$DUPS files are duplicated comparing $1 to $2."
}

LEFT=0
while [ $LEFT -lt ${#DIRS[@]} ] ; do
    RIGHT=$(( $LEFT + 1 ))
    while [ $RIGHT -lt ${#DIRS[@]} ] ; do
        count_dups ${DIRS[$LEFT]} ${DIRS[$RIGHT]}
        RIGHT=$(( $RIGHT + 1 ))
    done
    LEFT=$(( $LEFT + 1 ))
done

答案 3 :(得分:0)

我们可以为所有这24个目录创建哈希表吗? 如果文件名只是数字,则哈希函数将很容易设计。

如果我们可以使用哈希表,搜索和查找重复会更快。

答案 4 :(得分:0)

出于好奇,我做了一些简单的测试:24个目录,每个目录大约有3900个文件(0到9999之间的随机数)。两个bash脚本每个大约需要10秒。这是一个基本的python脚本在~0.2s内做同样的事情:

#!/usr//bin/python

import sys, os

def get_max_duplicates(path):
    items = [(d,set(os.listdir(os.path.join(path,d)))) \
        for d in os.listdir(path) if os.path.isdir(os.path.join(path, d))]
    if len(items) < 2: 
        # need at least two directories
        return ("","",0)
    values = [(items[i][0],items[j][0],len(items[i][1].intersection(items[j][1]))) \
        for i in range(len(items)) for j in range(i+1, len(items))]
    return max(values, key=lambda a: a[2])


def main():
    path = sys.argv[1] if len(sys.argv)==2 else os.getcwd()
    r = get_max_duplicates(path)
    print "%s and %s share %d files" % r

if __name__ == '__main__':
    main()

正如Richard所提到的,通过使用哈希表(或在python中设置),我们可以加快速度。两组的交集是O(min(len(set_a), len(set_b))),我们必须进行N(N-1)/2=720比较。