গ্রেপ: স্মৃতিশক্তি ক্লান্ত


42

আমি খুব সাধারণ অনুসন্ধান করছিলাম:

grep -R Milledgeville ~/Documents

এবং কিছু সময়ের পরে এই ত্রুটিটি উপস্থিত হয়েছিল:

grep: memory exhausted

আমি কীভাবে এড়াতে পারি?

আমার সিস্টেমে আমার 10 গিগাবাইট র‌্যাম রয়েছে এবং কয়েকটি অ্যাপ্লিকেশন চলছে, তাই আমি খুব আশ্চর্য হয়েছি যে একটি সাধারণ গ্রেপ মেমরির বাইরে চলে গেছে। ~/Documentsপ্রায় 100 গিগাবাইট এবং এতে সব ধরণের ফাইল রয়েছে।

grep -RI এই সমস্যা নাও থাকতে পারে তবে আমি বাইনারি ফাইলগুলিতেও অনুসন্ধান করতে চাই।

উত্তর:


46

দুটি সম্ভাব্য সমস্যা:

  • grep -R( grepওএস / এক্স ১০.৮ এবং তারপরে প্রাপ্ত সংশোধিত জিএনইউ ব্যতীত ) সিমলিংকগুলি অনুসরণ করে, সুতরাং কেবলমাত্র 100 জিবি ফাইল থাকা ~/Documentsসত্ত্বেও, /উদাহরণস্বরূপ একটি সিমিলিংক থাকতে পারে এবং আপনি ফাইলগুলি সহ পুরো ফাইল সিস্টেমটি স্ক্যান করে শেষ করতে পারেন even মত /dev/zero। ব্যবহার করুন grep -rনতুন গনুহ সঙ্গে grep, অথবা মান সিনট্যাক্স ব্যবহার করুন:

    find ~/Documents -type f -exec grep Milledgeville /dev/null {} +
    

    (তবে দ্রষ্টব্য যে প্রস্থানটির স্থিতিটি প্যাটার্নটি মিলেছে কি না তা সত্য প্রতিফলিত করে না)।

  • grepপ্যাটার্নের সাথে মেলে এমন লাইনগুলি খুঁজে পায়। তার জন্য, স্মৃতিতে এটি একবারে একটি লাইন লোড করতে হয়। grepঅন্যান্য অনেকগুলি grepবাস্তবায়নের বিপরীতে জিএনইউ বাইনারি ফাইলগুলিতে অনুসন্ধানের জন্য যে রেখাগুলি পড়ে এবং সমর্থন করে সেগুলির আকারের সীমা নেই। সুতরাং, যদি আপনি খুব বড় লাইনের (যেটি দুটি নতুন লাইন অক্ষরের সাথে খুব দূরে অ্যাপ্লিকেশন সহ) পাওয়া যায় তবে উপলব্ধ মেমরির চেয়ে বড় এটি ব্যর্থ হবে fail

    এটি সাধারণত একটি বিরল ফাইলের সাথে ঘটে। আপনি এটি দিয়ে পুনরুত্পাদন করতে পারেন:

    truncate -s200G some-file
    grep foo some-file
    

    যে চারপাশে কাজ করা কঠিন। আপনি এটি হিসাবে এখনও করতে পারেন (এখনও জিএনইউ সহ grep):

    find ~/Documents -type f -exec sh -c 'for i do
      tr -s "\0" "\n" < "$i" | grep --label="$i" -He "$0"
      done' Milledgeville {} +
    

    এটি ইনপুট খাওয়ানোর আগে NUL টি অক্ষরের ক্রমকে একটি নতুন লাইন চরিত্রে রূপান্তর করে grep। স্পার্স ফাইলগুলির কারণে সমস্যাটি এমন ক্ষেত্রে কাভার করবে।

    আপনি কেবলমাত্র বড় ফাইলগুলির জন্য এটি করে এটি অনুকূলিত করতে পারেন:

    find ~/Documents -type f \( -size -100M -exec \
      grep -He Milledgeville {} + -o -exec sh -c 'for i do
      tr -s "\0" "\n" < "$i" | grep --label="$i" -He "$0"
      done' Milledgeville {} + \)
    

    যদি ফাইলগুলি অপ্রয়োজনীয় না হয় এবং আপনার grepআগে GNU এর একটি সংস্করণ থাকে তবে 2.6আপনি --mmapবিকল্পটি ব্যবহার করতে পারেন । লাইনগুলি সেখানে অনুলিপি করার বিপরীতে মেমরিতে ম্যাপ করা হবে যার অর্থ সিস্টেম সর্বদা ফাইলে পৃষ্ঠাগুলি প্রেরণ করে মেমরিটিকে পুনরায় দাবি করতে পারে। এই বিকল্পটি জিএনইউ grep২.6-এ সরানো হয়েছে


প্রকৃতপক্ষে, জিএনইউ গ্রেপ 1 লাইনে পড়ার বিষয়ে চিন্তা করে না, এটি ফাইলের একটি বড় অংশকে একটি একক বাফারে পড়ে। "তদ্ব্যতীত, জিএনইউ গ্রেপ অ্যাভয়েডসকে নতুন লাইনে ইনপুট দেয়" " উত্স: list.freebsd.org/pipermail/freebsd-current/2010- অগাস্ট/…
গড্রিক Seer

4
@ গড্রিকসিয়ার, এটি এখনও ফাইলের একটি বড় অংশটি একটি একক বাফারে পড়তে পারে, তবে এটি যদি সেখানে স্ট্রিংটি খুঁজে না পেয়ে এবং একটি নতুন লাইন চরিত্র খুঁজে না পায়, তবে আমার বাজিটি হ'ল এটি একক বাফারটিকে স্মৃতিতে রাখে এবং এর মধ্যে পরবর্তী বাফারটি পড়ে, কারণ কোনও মিল খুঁজে পাওয়া গেলে এটি প্রদর্শন করতে হবে। সুতরাং, সমস্যাটি এখনও একইরকম। অনুশীলনে, 200 গিগাবাইট স্পার ফাইলের একটি গ্রেপ OOM এর সাথে ব্যর্থ হয়।
স্টাফেন চেজেলাস

1
@ গড্রিকসিয়ার, ভাল না। লাইনগুলি যদি সমস্ত ছোট হয় grepতবে এটি এখন পর্যন্ত প্রক্রিয়া করা বাফারগুলি বাতিল করতে পারে। কয়েক কিলোবাইটের বেশি মেমরি ব্যবহার না grepকরে আপনি yesঅনির্দিষ্টকালের জন্য আউটপুট দিতে পারেন । সমস্যা হল লাইন মাপ।
স্টাফেন চেজেলাস

3
জিএনইউ গ্রেপ --null-dataবিকল্পটি এখানে কার্যকর হতে পারে। এটি ইনপুট লাইন টার্মিনেটর হিসাবে নতুন লাইনের পরিবর্তে NUL এর ব্যবহারকে বাধ্য করে।
ইরুভর

1
@ 1_CR, ভাল পয়েন্ট, যদিও এটি আউটপুট লাইন টার্মিনেটরটিকে NUL এ সেট করে।
স্টাফেন চেজেলাস

5

আমি সাধারণত করি

find ~/Documents | xargs grep -ne 'expression'

আমি একগুচ্ছ পদ্ধতি ব্যবহার করে দেখেছি এবং এটি দ্রুততম হিসাবে খুঁজে পেয়েছি। মনে রাখবেন যে এটি ফাঁকা জায়গাগুলির সাথে ফাইলের নামটি খুব ভালভাবে পরিচালনা করে না। যদি আপনি জানেন যে এটি কেস এবং গ্রিপের একটি জিএনইউ সংস্করণ রয়েছে তবে আপনি এটি ব্যবহার করতে পারেন:

find ~/Documents -print0 | xargs -0 grep -ne 'expression'

যদি না হয় আপনি ব্যবহার করতে পারেন:

 find ~/Documents -exec grep -ne 'expression' "{}" \;

যা execপ্রতিটি ফাইলের জন্য গ্রেপ করবে ।


এটি স্পেস সহ ফাইলগুলিতে বিভক্ত হবে।
ক্রিস ডাউন

হুম, এটা সত্য।
কোট্ট

আপনি find -print0 | xargs -0 grep -ne 'expression'
এটির

@ ক্রিসডাউন একটি ভাঙ্গা-বহনযোগ্য সমাধানের চেয়ে একটি অ-প্রতিরক্ষামূলক সমাধান।
reto

@ ক্রিসডাউন বেশিরভাগ প্রধান সংস্থাগুলি গ্রহণ করেছে find -print0এবং xargs -0এখন পর্যন্ত: তিনটি বিএসডি, মিনিক্স 3, সোলারিস ১১, ...
গিলস'স-অশুভ হওয়া বন্ধ করুন '

4

আমি এটিকে ঘিরে ধরার কয়েকটি উপায় সম্পর্কে ভাবতে পারি:

  • একবারে সমস্ত ফাইল গ্রেপিংয়ের পরিবর্তে একবারে একটি ফাইল করুন। উদাহরণ:

    find /Documents -type f -exec grep -H Milledgeville "{}" \;
    
  • যদি আপনার কেবলমাত্র কোন ফাইলগুলিতে শব্দগুলি রয়েছে তা জানতে প্রয়োজন হয় তবে grep -lতার পরিবর্তে করুন। যেহেতু গ্রেপ সেখানে প্রথম হিট হওয়ার পরে অনুসন্ধান বন্ধ করবে, এটি কোনও বিশাল ফাইল পড়তে হবে না

  • আপনি যদি আসল পাঠ্যটিও চান তবে আপনি দুটি পৃথক গ্রেপগুলি স্ট্রিং করতে পারেন:

    for file in $( grep -Rl Milledgeville /Documents ); do grep -H Milledgeville "$file"; done
    

শেষ উদাহরণটি বৈধ সিনট্যাক্স নয় - আপনার একটি কমান্ড প্রতিস্থাপন সম্পাদন করা প্রয়োজন (এবং আপনার এটি করা উচিত নয়, যেহেতু grepফাইলের নামে বৈধ একটি ডিলিমিটার ব্যবহার করে ফলাফলগুলি)। আপনারও উদ্ধৃতি দেওয়া দরকার $file
ক্রিস ডাউন

দ্বিতীয় উদাহরণটি ফাইলের নামগুলির মধ্যে নতুন লাইন বা সাদা স্থান থাকার ইস্যুতে ভুগছে, (এটি forফাইলটিকে দুটি আর্গুমেন্ট হিসাবে প্রক্রিয়া করবে)
ড্রভ স্লোয়ান

@ ড্রাভস্লোয়ান আপনার সম্পাদনাটি উন্নতি করার পরেও আইনী ফাইলের নাম ভাঙবে।
ক্রিস ডাউন

1
হ্যাঁ আমি এটিকে রেখেছি কারণ এটি তার উত্তরের অংশ ছিল, আমি কেবল এটির উন্নতি করার চেষ্টা করেছি যাতে এটি চালিত হয় (যে ক্ষেত্রে ফাইলগুলিতে স্পেস / নিউলাইন ইত্যাদি নেই)।
ড্র স্লোয়ান

তার সংশোধন - তার, আমার ক্ষমা জেনি: /
ড্রভ স্লোয়ান

1

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

আমরা যে সমাধানটি নিয়ে এসেছি তা হ'ল ডিডি ব্যবহার করে খণ্ডগুলিতে ডিস্কটি পড়া এবং খণ্ডগুলি গ্রিপ করে। এটি কোড (বড়- গ্রেপ.শ):

#problem: grep gives "memory exhausted" error on 6TB disks
#solution: read it on parts
if [ -z $2 ] || ! [ -e $1 ]; then echo "$0 file string|less -S # greps in chunks"; exit; fi

FILE="$1"
MATCH="$2"

SIZE=`ls -l $1|cut -d\  -f5`
CHUNKSIZE=$(( 1024 * 1024 * 1 )) 
CHUNKS=100 # greps in (100 + 1) x 1MB = 101MB chunks
COUNT=$(( $SIZE / $CHUNKSIZE * CHUNKS ))

for I in `seq 0 $COUNT`; do
  dd bs=$CHUNKSIZE skip=$(($I*$CHUNKS)) count=$(( $CHUNKS+1)) if=$FILE status=none|grep -UF -a --context 6 "$MATCH"
done

1
আপনি ওভারল্যাপিং খণ্ডগুলি না পড়লে আপনি সম্ভবত খণ্ড সীমানায় ম্যাচগুলি মিস করবেন। ওভারল্যাপটি আপনি যে স্ট্রিংয়ের সাথে প্রত্যাশা করছেন তার চেয়ে কমপক্ষে বড় হতে হবে।
কুসালানন্দ

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