我想要完成的是获取目录中的所有文件并按其内容的唯一性列出/排序它们
例子:
假设我们的目录中有这 7 个文件
uniquefile1.txt, uniquefile2.txt, samefile1.txt, samefile2.txt, equalfile1.txt, equalfile2.txt, equalfile3.txt
其中 uniquefile1 和 uniquefile2 具有不同的内容,所有 Samefile.txt 具有彼此相同的内容,并且所有 equalfile.txt 具有彼此相同的内容
预期输出:
uniquefile1.txt
uniquefile2.txt
samefile1.txt, samefile2.txt
equalfile1.txt, equalfile2.txt, equalfile3.txt
我一直在搞散列和使用 md5sum,但没能得到任何东西来完成这个任务
我想使用 grep、xargs、sed、awk、find 和locate 等实用程序来完成此操作,如有必要,还可以与其他一些 coreutils 混合使用。
答案1
这是修改后的部分我昨天写的一个答案:
$ cksum file* | awk '{ ck[$1$2] = ck[$1$2] ? ck[$1$2] ", " $3 : $3 } END { for (i in ck) print ck[i] }'
file3, file5
file1, file2, file4
在您的情况下,您将使用*.txt
或 甚至*
(如果目录中只有您想要比较的文件)而不是file*
.
结果告诉我们file3
和file5
具有相同的内容,与file1
、file2
和file4
(在本例中)相同。
标准cksum
实用程序将为每个文件输出三列。第一个是校验和,第二个是文件大小,第三个是文件名。
该awk
代码将使用校验和和大小作为数组中的键ck
,并将具有相同键的文件名存储在该键的逗号分隔字符串中。最后,打印出文件名(逗号分隔的字符串)。
长相滑稽的
ck[$1$2] = ck[$1$2] ? ck[$1$2] ", " $3 : $3
只是意味着“如果ck[$1$2]
设置为任何内容,则分配ck[$1$2] ", " $3
给ck[$1$2]
(在文件名之间添加逗号),否则只分配$3
(这是带有此键的第一个文件名)”。
要根据每个列表中的项目数对输出进行排序,请将输出传递给
awk -F, '{ print NF, $0 }' | sort -n | cut -d ' ' -f 2-
...作为后处理阶段。如果任何文件名包含逗号,这显然会中断。
或者使用
cksum file* | awk '{ n[$1$2]++; ck[$1$2] = ck[$1$2] ? ck[$1$2] ", " $3 : $3 } END { for (i in ck) print n[i], ck[i] }' | sort -n | cut -d ' ' -f 2-
文件名中的逗号没有任何问题。
cut
如果您想查看每行输出上的文件名数量,请忽略该选项。
对于大量文件,您可能需要使用
find . -type f -exec cksum {} +
而不仅仅是
cksum *
答案2
我会用perl
:
perl -MDigest::SHA -le '
for $f (@ARGV) {
$d = Digest::SHA->new(256);
$d->addfile($f);
push @{$h{$d->digest}}, $f
}
print join ", ", @{$h{$_}} for keys %h' -- *.txt
我们正在构建一个关联数组,其键是文件的 sha256 哈希值,值是具有该哈希值的文件列表。
它可以轻松地按出现次数对输出进行排序,例如:
perl -MDigest::SHA -le '
for $f (@ARGV) {
$d = Digest::SHA->new(256);
$d->addfile($f);
push @{$h{$d->digest}}, $f
}
print join ", ", @{$h{$_}} for sort {@{$h{$a}} <=> @{$h{$b}}} keys %h' -- *.txt
或者甚至按文件名对每组中的文件列表进行排序:
perl -MDigest::SHA -le '
for $f (@ARGV) {
$d = Digest::SHA->new(256);
$d->addfile($f);
push @{$h{$d->digest}}, $f
}
print join ", ", sort {$a cmp $b} @{$h{$_}} for
sort {@{$h{$a}} <=> @{$h{$b}}} keys %h' -- *.txt