Bash命令根据内容列出所有文件

Bash命令根据内容列出所有文件

我想要完成的是获取目录中的所有文件并按其内容的唯一性列出/排序它们

例子:

假设我们的目录中有这 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*.

结果告诉我们file3file5具有相同的内容,与file1file2file4(在本例中)相同。

标准cksum实用程序将为每个文件输出三列。第一个是校验和,第二个是文件大小,第三个是文件名。

awk代码将使用校验和和大小作为数组中的键ck,并将具有相同键的文件名存储在该键的逗号分隔字符串中。最后,打印出文件名(逗号分隔的字符串)。

长相滑稽的

ck[$1$2] = ck[$1$2] ? ck[$1$2] ", " $3 : $3

只是意味着“如果ck[$1$2]设置为任何内容,则分配ck[$1$2] ", " $3ck[$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

相关内容