我希望你能解决以下问题。我有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个目录的问题变得非常大,所以我想我可能会使用强力方法。
的内容如果有人有办法这样做,我会非常感谢你提出一些建议。我想过使用fdupes
或diff
,但无法弄清楚如何解析输出和总结。
答案 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
比较。