web-dev-qa-db-ja.com

ディレクトリ内の一意のファイルのカウンター

私はプログラムを何度も実行しましたが、出力は(わずかに)非決定的でした。毎回、出力をファイルに出力しました。現在、多くのテキストファイル(95,034)のディレクトリがあり、おそらく4つの異なる一意の出力のようなものがあります。次のような形式で出力を確認したいと思います。

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

しかし、A、B、C、D(4つの異なる可能な出力)の内容を見るだけでも素晴らしいでしょう。 90,000ファイルを手動で重複除外する時間がありません。それでは、ディレクトリ内の一意のテキストファイルをカウントまたは一覧表示するにはどうすればよいですか?ありがとう!

5
jxmorris12

@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を1つ上のディレクトリに移動します。私の例では、.で作業しており、ファイルはtest/にあります。

4つのファイルタイプのそれぞれを1つ特定し、それらをファイルA、B、C、およびDにコピーすることをお勧めします(必要に応じて、Zまで)。

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

これで、一意の各出力ファイルA〜Zの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/に、ファイルA〜Dと一致しないMD5値を持つファイルがあります。つまり、どこかに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
4
Jim L.

私は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

ハッシュ5591 ...の27個のファイルがあり、そのうちの1つは「junk1」です。 (同様に、「junk2」と同じ17個のファイル、および「junk3」の7個のファイル)。

-Wは、フィールド区切り文字として空白を使用することを示しています。 -s -g 1は、フィールド1(ハッシュ)による並べ替えとグループ化を示します。 countはフィールド1または2のどちらでもかまいません。

-fは「入力行全体を印刷する」と言います。これには、集計結果を印刷するときに、見つかった各グループのfirst行の完全な行のみを印刷するという癖があります。この場合、すべてではなく、各dup-setに含まれるファイル名の1つが得られるため、問題なく機能します。

5
sitaram

これには、sortuniqを使用することもできます。ファイルが存在するフォルダー内から、次のように入力します。

find . -type f | awk '{ print "tr \\\\n @ < " $0 "; echo "}' | sh | sort | uniq --count

(GNU coreutils。)からuniqを使用しない場合は、uniq --countuniq -cに置き換えます。)

それはあなたに一度に結果を与えるはずです。単純化と高速化のために(ハッシュを回避するため)、改行を@に変換します。これは、元のファイルの一部ではない任意の単一文字である可能性があります。

(これは、サブフォルダー内のファイルが存在する場合、それらが含まれることを前提としています。別の前提は、ファイルに@文字がないことです。そうでない場合はコメントしてください。それに応じてコマンドを調整します。)

1
Ned64

ハッシュマップを使用して、すべての一意のファイルを収集します。ハッシュはコンテンツに依存するため、一意のコンテンツを持つファイルのみがハッシュマップのエントリを取得します。

declare -A unique_files
for file in *; do 
    unique_files["$(md5sum "$file" | cut -d ' ' -f 1)"]="$file"
done
echo "${unique_files[@]}"
0
Hielke Walinga