重複ファイルを見つける bash に関するアルゴリズムを書きたい
サイズオプションを追加するにはどうすればよいですか?
車輪を再発明しないでください。適切なコマンドを使用してください。
fdupes -r dir
http://code.google.com/p/fdupes/を参照してください(一部の Linux ディストリビューションにパッケージ化されています)。
find . -not -empty -type f -printf "%s\n" | sort -rn | uniq -d |\
xargs -I{} -n1 find . -type f -size {}c -print0 | xargs -0 md5sum |\
sort | uniq -w32 --all-repeated=separate
これはあなたがやりたい方法です。このコードは、最初にサイズに基づいて重複を特定し、次に MD5 ハッシュを特定します。-size
あなたの質問に関連して、の使用に注意してください。楽しみ。現在のディレクトリで検索することを想定しています。find .
そうでない場合は、検索したいディレクトリに適したものに変更してください。
find /path/to/folder1 /path/to/folder2 -type f -printf "%f %s\n" | sort | uniq -d
find コマンドは、ファイルの 2 つのフォルダーを検索し、ファイル名のみ (先頭のディレクトリを削除) とサイズ、並べ替え、重複のみを表示します。これは、ファイル名に改行がないことを前提としています。
通常、私は使用しますfdupes -r -S .
。しかし、非常に大きなファイルの少量の重複を検索すると、fdupes
ファイル全体の完全なチェックサムが実行されるため、終了するのに非常に時間がかかります(推測)。
最初の 1 メガバイトだけを比較することで、それを回避しました。それは超安全ではなく、100% 確実にしたい場合は、それが本当に重複しているかどうかを確認する必要があります。しかし、2 つの異なるビデオ (私の場合) の最初のメガバイトが同じで、その後のコンテンツが異なる可能性は、かなり理論的なものです。
だから私はこのスクリプトを書きました。高速化するためのもう 1 つのトリックは、特定のパスの結果のハッシュをファイルに保存することです。ファイルが変更されないという事実に依存しています。
このコードを実行するのではなく、コンソールに貼り付けます。そのためには、さらに作業が必要ですが、ここにアイデアがあります。
find -type f -size +3M -print0 | while IFS= read -r -d '' i; do
echo -n '.'
if grep -q "$i" md5-partial.txt; then
echo -n ':'; #-e "\n$i ---- Already counted, skipping.";
continue;
fi
MD5=`dd bs=1M count=1 if="$i" status=none | md5sum`
MD5=`echo $MD5 | cut -d' ' -f1`
if grep "$MD5" md5-partial.txt; then echo -e "Duplicate: $i"; fi
echo $MD5 $i >> md5-partial.txt
done
fi
## Show the duplicates
#sort md5-partial.txt | uniq --check-chars=32 -d -c | sort -b -n | cut -c 9-40 | xargs -I '{}' sh -c "grep '{}' md5-partial.txt && echo"
最大の重複ファイルを決定するために使用する別の bash スニペット:
## Show wasted space
if [ false ] ; then
sort md5-partial.txt | uniq --check-chars=32 -d -c | while IFS= read -r -d '' LINE; do
HASH=`echo $LINE | cut -c 9-40`;
PATH=`echo $LINE | cut -c 41-`;
ls -l '$PATH' | cud -c 26-34
done
これらのスクリプトは両方とも、改善の余地がたくさんあります。お気軽に貢献してください -ここに要点があります:)
cmp
次のようにファイルサイズを比較するために利用できます:
#!/bin/bash
folder1="$1"
folder2="$2"
log=~/log.txt
for i in "$folder1"/*; do
filename="${i%.*}"
cmp --silent "$folder1/$filename" "$folder2/$filename" && echo "$filename" >> "$log"
done