आपकी स्क्रिप्ट में कुछ समस्याएं हैं।
सबसे पहले, एक चर के लिए एक कमांड के परिणाम को निर्दिष्ट करने के लिए आपको इसे या तो बैकटिक्स ( `command`
) में संलग्न करना होगा या, अधिमानतः $(command)
,। आपके पास यह एकल उद्धरण ( 'command'
) में है जो आपके चर के लिए आपके कमांड के परिणाम को असाइन करने के बजाय, कमांड को एक स्ट्रिंग के रूप में असाइन करता है। इसलिए, आपका test
वास्तव में है:
$ echo "test $sum1=$sum2"
test find $i -type f -iname "*.jpg" -exec md5sum {} \;=find $j -type f -iname "*.jpg" -exec md5sum {} \;
अगला मुद्दा यह है कि कमांड md5sum
केवल हैश से अधिक वापस आता है:
$ md5sum /etc/fstab
46f065563c9e88143fa6fb4d3e42a252 /etc/fstab
आप केवल पहले क्षेत्र की तुलना करना चाहते हैं, इसलिए आपको md5sum
आउटपुट को एक कमांड के माध्यम से पास करके पार्स करना चाहिए जो केवल पहले क्षेत्र को प्रिंट करता है:
find $i -type f -iname "*.png" -exec md5sum '{}' \; | cut -f 1 -d ' '
या
find $i -type f -iname "*.png" -exec md5sum '{}' \; | awk '{print $1}'
इसके अलावा, find
कमांड कई मैचों को लौटाएगा, न कि केवल एक और उनमें से प्रत्येक मैच को दूसरे द्वारा दोहराया जाएगा find
। इसका मतलब यह है कि कुछ बिंदु पर आप उसी फ़ाइल की खुद से तुलना कर रहे होंगे, md5sum समान होगा और आप अपनी सभी फ़ाइलों को हटा देंगे (मैंने इसे परीक्षण dir युक्त पर चलाया ) a.jpg
और 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_path
जब तक आप निर्देशिकाओं की एक सरणी नहीं दे रहे हैं, तब तक आप चलाना नहीं चाहते हैं। यदि ये सभी फाइलें एक ही डायरेक्टरी में हैं, तो आप for i in $(find directory_path -iname "*.jpg"
सभी फाइलों से गुजरना चाहते हैं )।
यह है एक बुरा विचार का उपयोग करने के for
लिए ढूंढें के उत्पादन के साथ छोरों। आपको while
लूप या ग्लोबिंग का उपयोग करना चाहिए :
find . -iname "*.jpg" | while read i; do [...] ; done
या, यदि आपकी सभी फाइलें उसी निर्देशिका में हैं:
for i in *jpg; do [...]; done
आपके शेल और आपके द्वारा सेट किए गए विकल्पों के आधार पर, आप उपनिर्देशिकाओं में फ़ाइलों के लिए भी ग्लोबिंग का उपयोग कर सकते हैं, लेकिन चलो यहां नहीं मिलते हैं।
अंत में, आपको अपने चर को भी उद्धृत करना चाहिए और रिक्त स्थान के साथ निर्देशिका पथ आपकी स्क्रिप्ट को तोड़ देगा।
फ़ाइल नामों में रिक्त स्थान, नई लाइनें, बैकस्लैश और अन्य अजीब अक्षर हो सकते हैं, उन while
लूप में सही तरीके से निपटने के लिए जिन्हें आपको कई और विकल्प जोड़ने होंगे। आप जो लिखना चाहते हैं वह कुछ इस तरह है:
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
इससे भी सरल तरीका होगा:
find directory_path -name "*.jpg" -exec md5sum '{}' + |
perl -ane '$k{$F[0]}++; system("rm $F[1]") if $k{$F[0]}>1'
एक बेहतर संस्करण जो फ़ाइल नामों में रिक्त स्थान से निपट सकता है:
find directory_path -name "*.jpg" -exec md5sum '{}' + |
perl -ane '$k{$F[0]}++; system("rm \"@F[1 .. $#F]\"") if $k{$F[0]}>1'
यह थोड़ा पर्ल स्क्रिप्ट find
कमांड (यानी md5sum और फ़ाइल नाम) के परिणामों के माध्यम से चलेगा । -a
के लिए विकल्प perl
खाली स्थान के पर विभाजन इनपुट लाइनों और उन में बचत होती है F
सरणी, इसलिए $F[0]
md5sum और हो जाएगा $F[1]
फ़ाइल नाम। Md5sum हैश में सहेजा जाता है k
और स्क्रिप्ट जांचती है कि क्या हैश पहले से ही देखा गया है ( if $k{$F[0]}>1
) और फाइल को डिलीट कर देता है यदि यह ( system("rm $F[1]")
) है।
जबकि यह काम करेगा, यह बड़े छवि संग्रहों के लिए बहुत धीमा होगा और आप यह नहीं चुन सकते हैं कि कौन सी फाइल रखनी है। कई कार्यक्रम हैं जो इसे और अधिक सुरुचिपूर्ण तरीके से संभालते हैं: