目录中唯一文件的计数器

jxm*_*s12 5 shell-script text-processing files

我多次运行一个程序,输出(略微)不确定。每次,我都将输出打印到一个文件中。我现在有一个包含许多文本文件 (95,034) 的目录,其中可能有 4 个不同的独特输出。我很想看到这样的格式的输出:

 A (50,000)
 B (30,000)
 C (10,000)
 D  (5,034)
Run Code Online (Sandbox Code Playgroud)

但即使只是看到 A、B、C、D(四种不同的可能输出)的内容也会很棒。我没有时间手动删除 90,000 个文件的重复数据。那么如何计算或列出目录中的唯一文本文件呢?谢谢!

小智 5

我是 GNU 的忠实粉丝datamashhttps://www.gnu.org/software/datamash/)。这是我创建并运行此命令的一组模拟文件的示例输出:

$ md5sum * | datamash -W -s -g 1 count 2 -f
5591dadf0051bee654ea41d962bc1af0    junk1   27
9c08c31b951a1a1e0c3a38effaca5863    junk2   17
f1e5cbfade7063a0c4fa5083fd36bf1a    junk3   7
Run Code Online (Sandbox Code Playgroud)

有 27 个文件的哈希值为 5591...,其中之一是“junk1”。(与“junk2”相同的文件有 17 个,“junk3”有 7 个文件)。

-W说,使用空格作为字段分隔符。的-s -g 1说,排序和由场1(它是散列)基团。在count本来无论是现场1或2,无所谓。

-f写着“打印整个输入线”。这有一个怪癖,因为当您打印聚合结果时,它只打印它找到的每个组中第一行的整行。在这种情况下,效果很好,因为它为我们提供了每个 dup-set 中涉及的文件名之一,而不是所有文件名。


Jim*_* L. 4

稍微扩展@Isaac 的解决方案......

假设bash语法,并给出:

$ find test -type f
test/AA
test/A
test/C
test/CC
test/B
test/D
Run Code Online (Sandbox Code Playgroud)

其中文件 A 和 AA 相同,C 和 CC 也相同;

这是一个逐渐更有效的命令管道:

$ find test -maxdepth 1 -type f -exec bash -c "md5sum < {}" \; |
    sort -k1,1 |
    uniq --count
      2 102f2ac1c3266e03728476a790bd9c11  -
      1 4c33d7f68620b7b137c0ca3385cb6597  -
      1 88178a003e2305475e754a7ec21d137d  -
      2 c7a739d5538cf472c8e87310922fc86c  -
Run Code Online (Sandbox Code Playgroud)

现在剩下的问题是 md5 哈希值不会告诉您哪些文件是 A、B、C 或 D。这是可以解决的,尽管有点麻烦。

首先,将文件移至子目录中,或者如果更方便的话,将 PWD 移至上一个目录。在我的示例中,我正在工作.并且文件位于test/.

我建议您分别识别四种文件类型中的一种,并将它们复制到文件 A、B、C 和 D(如果需要,还可复制到文件 Z):

$ cp -p test/file1002 ./A
...
$ cp -p test/file93002 ./N
Run Code Online (Sandbox Code Playgroud)

等等。我们现在可以构建一个哈希表,定义每个唯一输出文件 AZ 的 md5 哈希值:

$ for file in [A-Z]; do 
      printf "s/%s/%s/\n" "$(md5sum < $file )" "$file"; 
done
s/102f2ac1c3266e03728476a790bd9c11  -/A/
s/4c33d7f68620b7b137c0ca3385cb6597  -/B/
s/c7a739d5538cf472c8e87310922fc86c  -/C/
s/88178a003e2305475e754a7ec21d137d  -/D/
Run Code Online (Sandbox Code Playgroud)

请注意,哈希表看起来像sed语法。原因如下:

让我们运行find ... md5sum上面相同的管道:

$ find test -maxdepth 1 -type f -exec bash -c "md5sum < {}" \; |
    sort -k1,1 |
    uniq --count
Run Code Online (Sandbox Code Playgroud)

...并将其通过一个sed使用上面的哈希表的过程进行管道传输,以将哈希值替换为原型文件名。该sed命令本身是:

sed -f <(
    for file in [A-Z]; do 
        printf "s/%s/%s/\n" "$(md5sum < "$file")" "$file"; 
    done
)
Run Code Online (Sandbox Code Playgroud)

因此,将它们连接在一起:

$ find test -maxdepth 1 -type f -exec bash -c "md5sum < {}" \; |
    sort -k1,1 |
    uniq --count |
    sed -f <(
        for file in [A-Z]; do 
            printf "s/%s/%s/\n" "$(md5sum < "$file")" "$file"; 
        done
    )
  2 A
  1 B
  1 D
  2 C
Run Code Online (Sandbox Code Playgroud)

如果您看到这样的输出:

  2 A
  1 B
  1 5efa8621f70e1cad6aba9f8f4246b383  -
  1 D
  2 C
Run Code Online (Sandbox Code Playgroud)

这意味着某个文件的test/MD5 值与您的文件 AD 不匹配。换句话说,E某处存在一种输出文件格式。一旦找到它(md5sum test/* | grep 5efa8621f70e1cad6aba9f8f4246b383),您可以将其复制到 E 并重新运行:

$ cp -p test/file09876 ./E
$ find test -maxdepth 1 -type f -exec bash -c "md5sum < {}" \; |
    sort -k1,1 |
    uniq --count |
    sed -f <(
        for file in [A-Z]; do 
            printf "s/%s/%s/\n" "$(md5sum < "$file")" "$file"; 
        done
    )
  2 A
  1 B
  1 E
  1 D
  2 C
Run Code Online (Sandbox Code Playgroud)