ডিরেক্টরিতে সদৃশ সন্ধান এবং সরিয়ে ফেলুন


12

আমার একাধিক ইমগ ফাইল সহ একটি ডিরেক্টরি রয়েছে এবং সেগুলির কয়েকটি অভিন্ন তবে তাদের সবার নাম আলাদা। আমাকে নকল সরিয়ে ফেলতে হবে তবে কেবল কোনও bashস্ক্রিপ্টের সাথে কোনও বাহ্যিক সরঞ্জাম নেই with আমি লিনাক্সের একজন শিক্ষানবিশ। আমি লুপের জন্য পরিমাণের তুলনা করতে md5এবং ফলাফল সরানোর উপর নির্ভর করে চেষ্টা করেছি কিন্তু সিনট্যাক্সে কিছু ভুল হয়েছে এবং এটি কার্যকর হয় না। কোন সাহায্য?

আমি যা চেষ্টা করেছি তা হ'ল ...

for i in directory_path; do
    sum1='find $i -type f -iname "*.jpg" -exec md5sum '{}' \;'
    for j in directory_path; do
        sum2='find $j -type f -iname "*.jpg" -exec md5sum '{}' \;'
        if test $sum1=$sum2 ; then rm $j ; fi
    done
done

আমি পাই: test: too many arguments


আপনার প্রশ্নটিতে যে কোনও ত্রুটি বার্তা পাবেন তাও অন্তর্ভুক্ত করুন।
টেরডন

আপনি কেন fdupes মত বাহ্যিক সরঞ্জাম ব্যবহার করতে পারবেন না? @ স্টারডনের উত্তরটি আশ্চর্যজনক, তবে কেন এটি সম্ভব হয় যদি একটি ভাল সরঞ্জাম ব্যবহার করা সম্ভব হয় তবে এটি সত্যই হাইলাইট করে। যদি এটি কোনও ধরণের ডেডিকেটেড হার্ডওয়্যার বা সার্ভার হয় তবে আপনি এখনও কোনও নেটওয়ার্ক ইত্যাদি মাধ্যমে এটি মেশিন থেকে fdupes এর মতো সরঞ্জাম উপলব্ধ থাকতে পারবেন।
জো

উত্তর:


28

আপনার স্ক্রিপ্টে বেশ কয়েকটি সমস্যা রয়েছে।

  • প্রথমত, কোনও ভেরিয়েবলের কমান্ডের ফলাফল নির্ধারণের জন্য আপনাকে এটি ব্যাকটিক্স ( `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_pathpassing এই সমস্ত ফাইল যদি একই ডিরেক্টরিতে থাকে তবে আপনি চালাতে চান 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]ফাইলের নাম। এমডি 5সাম হ্যাশে সংরক্ষিত হয়েছে kএবং স্ক্রিপ্টটি হ্যাশটি ইতিমধ্যে দেখা গেছে কিনা তা পরীক্ষা করে দেখুন ( if $k{$F[0]}>1) এবং এতে ফাইলটি মুছে ফেলা হলে ( system("rm $F[1]")) রয়েছে।


এটি যখন কাজ করবে তখন এটি বৃহত্তর চিত্র সংগ্রহের জন্য খুব ধীর হবে এবং কোন ফাইলগুলি রাখতে হবে তা আপনি চয়ন করতে পারবেন না। অনেকগুলি প্রোগ্রাম রয়েছে যা এটিকে আরও মার্জিত উপায়ে পরিচালনা করে:


পার্ল স্নিপেটের জন্য +1। সত্যিই মার্জিত! আপনি কল করার unlinkপরিবর্তে পার্লের নিজস্বও ব্যবহার করতে পারেন system
জোসেফ আর।

@JosephR। ধন্যবাদ :)। ত্রুটি থাকলেও এটি স্পেস সহ ফাইলের নামের জন্য ব্যর্থ হত কারণ প্রথম স্থান পর্যন্ত কোনও নামের প্রথম অক্ষরই থাকত $F[1]। অ্যারে স্লাইস ব্যবহার করে এটি স্থির করা হয়েছে। লিঙ্কমুক্ত () আমি জানি, তবে পেরিলিসমগুলি সর্বনিম্ন রাখতে চেয়েছিলাম এবং পার্লকে না জানলে সিস্টেম কলটি বোঝা সহজ।
টেরডন

13

একটি নিফটির প্রোগ্রাম রয়েছে যা fdupesপুরো প্রক্রিয়াটিকে সহজ করে তোলে এবং নকল মুছতে ব্যবহারকারীকে অনুরোধ করে। আমি মনে করি এটি যাচাইযোগ্য:

$ fdupes --delete DIRECTORY_WITH_DUPLICATES
[1] DIRECTORY_WITH_DUPLICATES/package-0.1-linux.tar.gz        
[2] DIRECTORY_WITH_DUPLICATES/package-0.1-linux.tar.gz.1

Set 1 of 1, preserve files [1 - 2, all]: 1

   [+] DIRECTORY_WITH_DUPLICATES/package-0.1-linux.tar.gz
   [-] DIRECTORY_WITH_DUPLICATES/package-0.1-linux.tar.gz.1

মূলত, এটি আমাকে কোন ফাইলটি রাখার জন্য জিজ্ঞাসা করেছিল , আমি 1 টাইপ করেছি এবং এটি দ্বিতীয়টি সরিয়ে ফেলে।

অন্যান্য আকর্ষণীয় বিকল্পগুলি হ'ল:

-r --recurse
    for every directory given follow subdirectories encountered within

-N --noprompt
    when used together with --delete, preserve the first file in each set of duplicates and delete the others without prompting the user

আপনার উদাহরণ থেকে, আপনি সম্ভবত এটি চালাতে চান:

fdupes --recurse --delete --noprompt DIRECTORY_WITH_DUPLICATES

man fdupesউপলব্ধ সমস্ত বিকল্পের জন্য দেখুন ।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.