Senaryonuzda birkaç problem var.
İlk olarak , bir komutun sonucunu bir değişkene atamak için , onu backtics ( `command`) veya tercihen, içine almanız gerekir $(command). 'command'Komutunuzun sonucunu değişkeninize atamak yerine, komutun kendisini dize olarak atayan tek tırnak işareti ( ) kullanırsınız. Bu nedenle, testaslında:
$ echo "test $sum1=$sum2"
test find $i -type f -iname "*.jpg" -exec md5sum {} \;=find $j -type f -iname "*.jpg" -exec md5sum {} \;
Bir sonraki sorun, komutun md5sumkarma değerinden fazlasını döndürmesidir:
$ md5sum /etc/fstab
46f065563c9e88143fa6fb4d3e42a252 /etc/fstab
Yalnızca ilk alanı karşılaştırmak istiyorsunuz, bu nedenle md5sumçıktıyı yalnızca ilk alanı yazdıran bir komuttan geçirerek ayrıştırmalısınız :
find $i -type f -iname "*.png" -exec md5sum '{}' \; | cut -f 1 -d ' '
veya
find $i -type f -iname "*.png" -exec md5sum '{}' \; | awk '{print $1}'
Ayrıca, findkomut birçok eşleşmeyi döndürür, yalnızca bir tane değil, bu eşleşmelerin her biri ikincisi tarafından çoğaltılır find. Bir noktada kendisine aynı dosyayı karşılaştırarak olacağını Bu araçlar, md5sum özdeş olacak ve silme sona erecek tüm dosyalarınızı (ı içeren bir test dir bu koştum a.jpgve b.jpg):
for i in $(find . -iname "*.jpg"); do
for j in $(find . -iname "*.jpg"); do
echo "i is: $i and j is: $j"
done
done
i is: ./a.jpg and j is: ./a.jpg ## BAD, will delete a.jpg
i is: ./a.jpg and j is: ./b.jpg
i is: ./b.jpg and j is: ./a.jpg
i is: ./b.jpg and j is: ./b.jpg ## BAD will delete b.jpg
for i in directory_pathBir dizi dizini geçmediğiniz sürece çalıştırmak istemezsiniz . Tüm bu dosyalar aynı dizindeyse, çalıştırmak istediğiniz for i in $(find directory_path -iname "*.jpg") tüm dosyaları gözden geçirin.
Öyle kötü bir fikir kullanmak forfind çıkışı ile döngüler. whileDöngüler veya globbing kullanmalısınız :
find . -iname "*.jpg" | while read i; do [...] ; done
veya tüm dosyalarınız aynı dizindeyse:
for i in *jpg; do [...]; done
Kabuğunuza ve belirlediğiniz seçeneklere bağlı olarak, alt dizinlerdeki dosyalar için bile globbing kullanabilirsiniz, ancak buraya girmeyelim.
Son olarak, değişkenlerinizi başka yerlere de eklemelisiniz. Boşluklu dizin yolları betiğinizi bozacaktır.
Dosya adları boşluklar, yeni satırlar, ters eğik çizgiler ve diğer garip karakterler içerebilir, bir whiledöngüde doğru olanlarla başa çıkmak için biraz daha seçenek eklemeniz gerekir. Yazmak istediğiniz şey şudur:
find dir_path -type f -iname "*.jpg" -print0 | while IFS= read -r -d '' i; do
find dir_path -type f -iname "*.jpg" -print0 | while IFS= read -r -d '' j; do
if [ "$i" != "$j" ]
then
sum1=$(md5sum "$i" | cut -f 1 -d ' ' )
sum2=$(md5sum "$j" | cut -f 1 -d ' ' )
[ "$sum1" = "$sum2" ] && rm "$j"
fi
done
done
Daha da basit bir yol:
find directory_path -name "*.jpg" -exec md5sum '{}' + |
perl -ane '$k{$F[0]}++; system("rm $F[1]") if $k{$F[0]}>1'
Dosya adlarındaki boşluklarla başa çıkabilen daha iyi bir sürüm:
find directory_path -name "*.jpg" -exec md5sum '{}' + |
perl -ane '$k{$F[0]}++; system("rm \"@F[1 .. $#F]\"") if $k{$F[0]}>1'
Bu küçük Perl betiği findkomutun sonuçları üzerinden çalışacaktır (md5sum ve dosya adı gibi). -aSeçeneği perlboşluktan böler girdi hatları ve bunları kaydeder Fböylece, dizinin $F[0]md5sum ve olacaktır $F[1]dosya adı. Md5sum karmaya kaydedilir kve komut dosyası karmanın daha önceden göründüğünü ( if $k{$F[0]}>1) kontrol eder ve ( ) varsa dosyayı siler system("rm $F[1]").
Bu işe yarayacak olsa da, büyük resim koleksiyonları için çok yavaş olacaktır ve hangi dosyaların saklanacağını seçemezsiniz. Bunu daha zarif bir şekilde ele alan birçok program vardır: