Shell-Script

目錄中唯一文件的計數器

  • October 25, 2019

我多次執行一個程序,其輸出(略微)不確定。每次,我都將輸出列印到文件中。我現在有一個包含許多文本文件 (95,034) 的目錄,其中可能有 4 個不同的獨特輸出。我希望以如下格式查看輸出:

A (50,000)
B (30,000)
C (10,000)
D  (5,034)

但即使只是看到 A、B、C、D 的內容(四種不同的可能輸出)也會很棒。我沒有時間手動刪除 90,000 個文件。那麼如何計算或列出目錄中的唯一文本文件呢?謝謝!

稍微擴展@Isaac 的解決方案….

假設bash語法,並給出:

$ find test -type f
test/AA
test/A
test/C
test/CC
test/B
test/D

其中文件 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  -

現在剩下的問題是 md5 雜湊不會告訴您哪些文件是 A、B、C 或 D。這可以解決,儘管它有點繁瑣。

首先,將您的文件移動到一個子目錄中,或者如果這樣更方便的話,將您的 PWD 上移一個目錄。在我的範例中,我正在工作.並且文件位於test/.

我建議您辨識四種文件類型中的每一種,並將它們複製到文件 A、B、C 和 D(如果需要,還可以復製到 Z):

$ cp -p test/file1002 ./A
...
$ cp -p test/file93002 ./N

等等。我們現在可以建構一個雜湊表,定義每個唯一輸出文件 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/

請注意,雜湊表看起來像sed語法。原因如下:

讓我們在上面執行相同的find ... md5sum管道:

$ find test -maxdepth 1 -type f -exec bash -c "md5sum < {}" \; |
   sort -k1,1 |
   uniq --count

sed…並通過使用上面的雜湊表將雜湊值替換為原型文件名的過程對其進行管道傳輸。該sed命令本身將是:

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

因此,將它們連接在一起:

$ 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

如果你看到這樣的輸出:

 2 A
 1 B
 1 5efa8621f70e1cad6aba9f8f4246b383  -
 1 D
 2 C

這意味著有一個文件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

datamash我是 GNU ( https://www.gnu.org/software/datamash/ )的忠實粉絲。這是我創建並執行此命令的一組模擬文件的範例輸出:

$ md5sum * | datamash -W -s -g 1 count 2 -f
5591dadf0051bee654ea41d962bc1af0    junk1   27
9c08c31b951a1a1e0c3a38effaca5863    junk2   17
f1e5cbfade7063a0c4fa5083fd36bf1a    junk3   7

有 27 個文件的雜湊值為 5591…,其中一個是“junk1”。(與“junk2”相同的文件有 17 個,與“junk3”相同的文件有 7 個)。

說使用-W空格作為欄位分隔符。-s -g 1表示按欄位 1(即雜湊)排序和分組。可能是count欄位 1 或 2,沒關係。

說“-f列印整個輸入行”。這有一個怪癖,因為當您列印聚合結果時,它只列印它找到的每個組中*第一行的完整行。*在這種情況下,效果很好,因為它為我們提供了每個 dup-set 中涉及的文件名之一,而不是所有文件名。

引用自:https://unix.stackexchange.com/questions/548225