1つのディレクトリの下のツリーにたくさんの音楽があり、品質のために最初に取得した形式で保存されています。構造が似ている2番目のディレクトリツリーがありますが、すべてのファイルが不可逆圧縮形式で携帯電話で再生でき、メタデータがときどき変更されます(たとえば、スペースを節約するために埋め込まれたカバーを削除します)。
音楽のかなりの部分で、2つのインスタンスの間に違いはないことに気づきました。通常、配布バージョンはmp3/oggとしてのみ入手可能で、カバーが埋め込まれていませんでした。ハードドライブのスペースは安いかもしれませんが、それはそれを無駄にする理由ではありません。スクリプトを作成する方法はありますか?
以下では、_md5
_を使用して、現在のディレクトリ以下のすべてのファイルのMD5ダイジェストを生成します。
_find . -type f -exec md5 {} +
_
BSD _md5
_ユーティリティがない場合は、_md5sum --tag
_を_md5
_に置き換えます。
ディレクトリでそれを行うための簡単なスクリプトを作成しましょう。
_#!/bin/bash
tmpdir=${TMPDIR:-/tmp}
if (( $# != 2 )); then
echo 'Expected two directories as arguments' >&2
exit 1
fi
i=0
for dir in "$@"; do
(( ++i ))
find "$dir" -type f -exec md5 {} + | sort -t '=' -k2 -o "$tmpdir/md5.$i"
done
_
これにより、コマンドラインで2つのディレクトリが取得され、_md5.1
_(または_md5.2
_が指している場所)に_/tmp
_および_$TMPDIR
_というファイルが各ディレクトリに1つずつ生成されます。これらのファイルは、MD5ダイジェストでソートされます。
ファイルは次のようになります
_MD5 (<path>) = <MD5 digest>
_
ファイルごとにそのような行が1つあります。
次に、同じスクリプトで、2つのファイル間のチェックサムを比較します。
_join -t '=' -1 2 -2 2 "$tmpdir"/md5.[12]
_
これは、チェックサムを結合フィールドとして使用して、2つのファイル間でリレーショナル「結合」操作を実行します。 2つのフィールドに同じチェックサムがある行はすべてマージされて出力されます。
チェックサムが両方のファイルで同じである場合、次のように出力されます。
_<space><MD5 digest>=MD5 (<path1>) =MD5 (<path2>)
_
これをawk
に直接渡して、2つのパスを解析することができます。
_awk -F '[()]' 'BEGIN { OFS="\t" } { print $2, $4 }'
_
-F [()]
は、各行を_(
_と_)
_に基づいてフィールドに分割したいという言い方です。これを行うと、フィールド2と4にパスが残ります。
これは出力します
_<path1><tab><path2>
_
次に、タブで区切られたこれらのパスのペアを読み取り、正しいコマンドを発行してリンクを作成するだけです。
_while IFS=$'\t' read -r path1 path2; do
echo ln -f "$path1" "$path2"
done
_
要約すれば:
_#!/bin/bash
tmpdir=${TMPDIR:-/tmp}
if (( $# != 2 )); then
echo 'Expected two directories as arguments' >&2
exit 1
fi
i=0
for dir in "$@"; do
(( ++i ))
find "$dir" -type f -exec md5 {} + | sort -t '=' -k2 -o "$tmpdir/md5.$i"
done
join -t '=' -1 2 -2 2 "$tmpdir"/md5.[12] |
awk -F '\\)|\\(' 'BEGIN { OFS="\t" } { print $2, $4 }' |
while IFS=$'\t' read -r path1 path2; do
echo ln -f "$path1" "$path2"
done
rm -f "$tmpdir"/md5.[12]
_
echo
ループのwhile
は、安全のためにあります。一度実行して何が起こるかを確認し、それが正しいことをしていると確信できる場合は、それを削除して再度実行します。
ハードリンクはパーティションにまたがることができないことに注意してください。これは、両方のディレクトリが同じパーティションに存在する必要があることを意味します。 secondディレクトリ内のファイルは、重複していることが判明した場合に上書きされます。結果に満足するまで、オリジナルのバックアップをどこかに保管してください。
ファイル名に_(
_または_)
_またはタブが含まれている場合、このソリューションは正しく機能しないことに注意してください。
非常に類似したファイルの大規模なコレクションがない限り、ハッシュを計算して比較しても、重複を見つけるプロセスは高速化されません。最も遅い操作はディスクの読み取りです。ハッシュを計算するということは、ファイル全体を読み取ることを意味します。また、最新の暗号的に強力なハッシュを使用するCPU集中型のタスクです。
ファイルの長さが異なる場合にのみ、データを比較する必要があります。指定された長さのファイルが1つしかない場合は、明らかに重複はありません。 2つある場合は、ハッシュよりも単純に比較する方が常に効率的です。 3つ以上ある場合、比較の数は増えますが、最初のバイトまたはブロックが異なる可能性があるため、ディスクI/Oは依然として低く、繰り返しの読み取りがキャッシュから返されます。
そのため、長さ+パス名のリストを準備する再帰的なディレクトリリストを作成し、リストを数値で並べ替えて、最後にペアごとに比較して同じ長さを共有するファイルのセットのみを処理することをお勧めします。 2つのファイルが一致する場合、1つはハードリンクに置き換えることができます。