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

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

プログラムを何度も実行しましたが、出力が(少し)不確実でした。毎回出力をファイルに印刷します。私は現在多くのテキストファイル(95,034)を含むディレクトリを持っており、そのうち4つの異なる固有の出力があるかもしれません。次の形式で出力を見たいです。

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

しかし、A、B、C、D(4つの可能な出力)がどのように見えるかを見るだけで良いでしょう。 90,000個のファイルを手動で重複排除する時間はありません。それでは、ディレクトリ内の一意のテキストファイル数をどのように計算または一覧表示しますか?ありがとうございます!

答え1

私は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個あります。その一つは「junk1」です。 (同様に、「junk2」と同じファイルが17個、「junk3」と同じファイルが7個あります。)

-Wフィールド区切り文字としてスペースを使用することを示します。-s -g 1フィールド1(ハッシュ値など)に基づいてソートとグループ化を示します。フィールド 1 であってもcountフィールド 2 であっても構いません。

-f「フル入力行を印刷します」と表示されます。ここには珍しい点があります。集計結果を印刷すると、行全体のみが印刷されます。最初各グループで行を探します。この場合、完全ではなく各反復セットに関連するファイル名の1つを提供するので、うまく機能します。

答え2

@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/

4つのファイル形式をそれぞれ識別して、ファイル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

答え3

この目的でsortおよびを使用することもできます。uniqファイルがあるフォルダーで、次のように入力します。

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

(を使用していない場合は、GNU coreutilsと交換してくださいuniq --count。)uniq -cuniq

これにより、一度に結果が得られます。単純さと速度(ハッシュ防止)のために、改行文字を次に変換します。@これは、元のファイルに属さない単一文字である可能性があります。

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

答え4

ハッシュマップを使用してすべての固有ファイルを収集します。ハッシュはコンテンツによって異なるため、固有のコンテンツを持つファイルだけがハッシュマップにアイテムを取得します。

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

関連情報