同じコンテンツを含む重複フォルダを検出する

同じコンテンツを含む重複フォルダを検出する

名前は異なりますが、内容は同じフォルダがあることがよくあります。

たとえば、アクセスしやすくするためにフォルダを別の場所にコピーし、そのコピーを削除するのを忘れていました。

同じ内容を含む重複フォルダをどのように検出しますか?

重複ファイルを検索するためにCzkawkaを使用しましたが、重複フォルダを検索するための同様のツールが見つかりませんでした。

エマルジョン:

重複フォルダを検出しますが、空のフォルダの存在は無視します。 https://stackoverflow.com/questions/43560796/how-to-find-duplicate-directories

重複フォルダを検出しますが、フォルダ名が重要です。 重複ディレクトリの検索と一覧表示

答え1

リント重複ディレクトリを検出する機能があります。

-D --merge-directories (default: disabled)

マニュアルページから:

作るリント特殊モードを使用して、見つかったすべての重複エントリを収集し、ディレクトリツリー全体で重複エントリを確認します。注意して使用してください。 rmlintまたはそのアンインストールスクリプトの実行中に調査中のディレクトリが変更されていないことを常に確認してください。

重要:同じ定義:rmlintは、データを含むファイルの名前の指定方法に関係なく、まったく同じデータを含む2つのディレクトリを同じと見なします。 rmlintがディレクトリ内のデータから長く整列したストリームを作成し、それを魔法のように他のディレクトリと比較すると想像してください。これは、デフォルトではディレクトリのレイアウトが重要ではないことを意味します。空のファイルもコンテンツとは見なされません。一部のユーザーにとって、これは驚くほど感じるかもしれませんが、rmlintは通常コンテンツに興味があり、他のメタデータやレイアウトには興味がないことに注意してください。同じ階層を持つツリーのみを検索するには、 --honour-dir-layout/-j を使用する必要があります。

答え2

この問題を解決する最も簡単な方法はもちろんです最初から問題はありませんでした。;あなたは不変のファイルセットに興味があるようですので、cp -r original second代わりに、を使用し、ln -s original secondLinuxがすでにすべてのフォルダやファイルをファイルシステム階層の異なるポイントに「ミラーリング」できるという事実を活用できます。

データの2番目のインスタンスでファイルを変更する機能が必要な場合は、参照カウントファイルシステム(XFS、btrfsなど)を使用してコピーがあることを無視することをお勧めします。変更はありません。使用しているファイルのコピーに余分なスペースを使用しないでください。

今、どちらもオプションではないとします。

すべてのディレクトリをすべてのディレクトリと比較する必要があるため(幸いにも1つのファイルシステムに滞在し、シンボリックリンクに従わない限りループはありません)、ツリー検索でサブツリーを複製する必要があります。私はシェルスクリプトがグラフデータ構造を扱う環境ではないと思います。シェルの複雑さと人間のプログラマーの両方にとって、それは急速に爆発します。

Rust、C++、Go、Erlang...を磨いてコーディングを始めましょう。

ディレクトリツリーのメモリ内表現を準備するには、ディレクトリ構造を再現する深さ優先検索アルゴリズムを作成する必要があります。各ノードには値(64ビット整数など)があり、最初に処理されたかどうかは、処理済みとしてマークされたノードはありません。

次に、そのツリーからリーフノード(つまり、他のディレクトリを含まないディレクトリ)を取得し、その中にあるファイルセットのハッシュを計算します(安定してソートされた方法で、ハッシュにはユーザーが興味を持っている内容、つまり修正時間、名前、サイズ、内容)? ...)対応するハッシュは対応するリーフノードの値になり、そのノードを処理済みとしてマークし、それをハッシュマップに入力します(ノード値をハッシュとして使用)。値がすでにハッシュマップのキーである場合は、実際のIDを確認し(ハッシュ関数はこれを保証しません!)、適切なコピーを削除してツリーからそのノードを削除します。

すべてのリーフノードを処理済みとしてマークした後(ツリーから削除した場合でも)、最初のリーフノードの最初の親に移動してディレクトリの内容をハッシュします。今回は、ノードを「処理済みとしてマーク」します。ファイルを独自のノードを持つ通常のノードとして扱います。適切なハッシュ値。これにより、最初の親ノードの値が取得されます。これを処理済みとしてマークし、ハッシュテーブルに追加し、必要に応じて削除し、次にリーフノードに移動して同じことを行います。
そのディレクトリナビゲーションを実行すると、リーフノードとリーフノードのすべての兄弟エントリ(これは1つのディレクトリにのみ存在し、ツリー内の「親」に同じコピーを持つことはできません。別の深さサブディレクトリ)。

完了すると、前の「リーフの2番目のレベル」ノードがリーフノードになります。ルートノードに値が割り当てられるまでこの操作を繰り返します。

答え3

練習として、シェルに冗長ディレクトリ検索を実装しました。

https://github.com/ilario/finddirdupes

最初のパラメーターは分析するフォルダー、2番目のパラメーターは考慮する必要がある最小ディレクトリサイズ(バイト単位)です。多くの空のフォルダが検出されないようにするには、少なくとも5000を使用することをお勧めします。

./finddirdupes.sh ~/documents 10000

明らかに、rmlint -D他のコメントに報告されているよりもはるかに遅いです。

答え4

このコードはファイルの内容が同じであることを確認しないため、直接確認する必要があります。

サイズとサブフォルダー、含まれているファイル名に基づいてフォルダーを比較します。

実行する前に、コマンド-sオプションがls -sシステムに適していることを確認してください。

# avoid starting with a non-empty dirhash file
rm dirhash

# while reads all the folders list provided by find (the <<< is a here string, passing the find output as an input to read)
# cd enters the folder
# ls lists the content, -1 on only one column, -a including the hidden files, -s indicating the files size (check if this works on your system), -R recursively entering every subdirectory
# xxhsum calculates a string from the output of ls
# the XXH3 hashing algorithm was the one suggested on
# https://xxhash.com/#benchmarks.
# du calculates the total size of the folder
while read d; do cd "$d"; hash=$(ls -1asR | xxhsum -H3); size=$(du -s); cd "$OLDPWD"; echo $hash $size $d >> dirhash; done <<< $(find ./ -type d)

# sort sorts the file based on the dir size, and then on the hash
# uniq shows all the duplicates based on the first 38 characters, which include the hash and the size from du
sort -k5n,5 -k4,4 dirhash | uniq --all-repeated=separate -w 38

関連情報