البحث في الموقع
المحتوى عن 'grep'.
-
قد تشعر كمبرمج بالضياع عند استكشافك لأول مرة شيفرة مصدرية تحتوي على الآلاف من الأسطر، في هذه الحالة سيفيدك استخدام الأداة grep كثيرًا لحل تلك المشكلة، لذا سنستعرض في هذا المقال عدة طرق مفيدة لاستخدام الأمر grep على لينكس مع أمثلة عليها. أمثلة واقعية ومفيدة للأمر grep في لينكس يصف الدليل man الأداة grep على أنها أداة لطباعة الأسطر المُطابقة لنمط ما، قد ينتقص ذلك الوصف من الإمكانيات والاستخدامات العديدة للأمر grep، والتي تعد من أفضل الأدوات ضمن حزمة أدوات نظام يونكس، حيث ستجد نفسك بحاجة إليها في الكثير من الحالات عند تعاملك مع الملفات النصية. تعد الأمثلة الواقعية أفضل مُعلم، سنوضح الاستخدامات المتعددة للأداة grep بتطبيق أمثلتنا في هذا المقال على الشيفرة المصدرية للمكتبة Asciidoctor.js، يمكن تنزيل الشيفرة المصدرية للمكتبة من Github واختيار نفس الإصدار الذي تم تطبيق الأمثلة في هذا المقال عليه، وذلك للحصول على نتائج مطابقة للأمثلة المذكورة خلال تطبيق الأمثلة، يمكنك تنفيذ الأوامر التالية لتحميل الشيفرة المصدرية محليًا وتحديد الإصدار المطلوب العمل ضمنه: git clone https://github.com/asciidoctor/asciidoctor.js cd asciidoctor.js git checkout v1.5.6-rc.1 1. الاستخدام الأساسي بالبحث عن نص توفر Asciidoctor.js دعمًا لمحرك جافاسكريبت Nashorn لمنصة جافا، يمكننا البحث عن أماكن ذكر ذلك المحرك ضمن الشيفرة المصدرية للتعرف ولاستكشاف طريقة استخدام المكتبة له، يمكننا مثلًا البحث ضمن ملف توصيف الاعتماديات package.json عن كل ذكر لاسم المحرك Nashorn كالتالي: $ grep nashorn package.json "test": "node npm/test/builder.js && node npm/test/unsupported-features.js && node npm/test/jasmine-browser.js && node npm/test/jasmine-browser-min.js && node npm/test/jasmine-node.js && node npm/test/jasmine-webpack.js && npm run test:karmaBrowserify && npm run test:karmaRequirejs && node npm/test/nashorn.js", كما نلاحظ يوجد عدة اختبارات متعلقة بـ Nashorn، في المثال التالي سنحاول البحث أكثر عن استخدامات ذلك المحرك. 2. بحث غير حساس لحالة الأحرف ضمن مجموعة من الملفات يمكننا البحث ضمن ملفات الاختبار التي وجدنا ذكر لها في المثال السابق، التي تقع ضمن المجلد ./npm/test/ والتي تحوي على ذكر مباشر لكلمة Nashorn، في هذه الحالة البحث الغير حساس لحالة الأحرف أفضل، بحيث ستظهر لنا جميع حالات ذكر اسم المكتبة مثل "nashorn" و"Nashorn" أو أي شكل آخر للكلمة مؤلف من حروف كبيرة وصغيرة، وذلك باستخدام الخيار -i كالتالي: $ grep -i nashorn npm/test/*.js npm/test/nashorn.js:const nashornModule = require('../module/nashorn'); npm/test/nashorn.js:log.task('Nashorn'); npm/test/nashorn.js:nashornModule.nashornRun('jdk1.8.0'); نلاحظ من النتائج التي ظهرت فائدة البحث الغير حساس لحالة الأحرف في تلك الحالات، حيث لم يظهر في المثال الأول ضمن النتائج العبارة التالية require('../module/nashorn')، سنعاين هذا الملف بالتفصيل لاحقًا. 3. البحث عن الملفات الغير مطابقة سنحاول معرفة ما إذا كان يوجد ملفات لا تتعلق بمحرك Nashorn ضمن المجلد npm/test/، يمكننا عكس نتيجة البحث والاستفادة من خيار طباعة الملفات الغير مطابقة لشرط البحث -L كالتالي: sh$ grep -iL nashorn npm/test/* npm/test/builder.js npm/test/jasmine-browser-min.js npm/test/jasmine-browser.js npm/test/jasmine-node.js npm/test/jasmine-webpack.js npm/test/unsupported-features.js نلاحظ كيف أظهر لنا الأمر grep باستخدام الخيار -L ضمن الخرج أسماء تلك الملفات فقط، لا تحوي كل تلك الملفات على أي ذكر للنص "nashorn" ضمنها (بغض النظر عن حالة الأحرف للكلمة)، لا يعني ذلك أن تلك الملفات لا تتعلق بالمحرك nashorn، بل هي فقط لا تحوي على أحرف تلك الكلمة متتالية معًا. 4. البحث عن الأنماط ضمن الملفات المخفية والمجلدات الفرعية تكراريًا استخدمنا في آخر مثالين نمط glob لتحديد الملفات التي نريد من الأمر grep البحث ضمنها، لكن استخدام رمز النجمة ("*") يمنعنا من البحث ضمن الملفات المخفية، وكذلك ضمن الملفات الموجودة داخل المجلدات الفرعية، يمكن حل تلك المشكلة بدمج الأمر grep مع أمر البحث عن الملفات find بدلًا من الاعتماد على تمرير نمط glob الخاص بالصَدفة بإحدى الطريقتين: # الطريقة التالية غير فعالة، ستولد إجرائية جديدة لكل ملف $ find npm/test/ -type f -exec grep -iL nashorn \{} \; # الطريقة التالية تسبب مشاكل للملفات التي يحوي اسمها على فراغ $ grep -iL nashorn $(find npm/test/ -type f) لكل من الطريقتين السابقتين مساوؤها كما هو مذكور ضمن التعليقات فوق الأوامر، فلحل مشكلة أسماء الملفات التي تحتوي على فراغ يمكنك البحث أكثر عن كيفية استخدام الخيار grep -z مع الخيار -print0 للأمر find،لكن الحل الأمثل يكون باستخدام خيار البحث التكراري-r للأمر grep، وعندها يمكننا تحديد المجلد الجذر الذي نريد البحث ضمنه فقط، بدلًا من تمرير قائمة بأسماء الملفات المراد البحث فيها، سيبحث الأمر grep ضمن كل الملفات في المجلد المحدد، بما فيها المجلدات المخفية، ومن ثم سينزل تكراريًا إلى داخل المجلدات الفرعية ويعيد العملية: $ grep -irL nashorn npm/test/npm/ npm/test/builder.js npm/test/jasmine-browser-min.js npm/test/jasmine-browser.js npm/test/jasmine-node.js npm/test/jasmine-webpack.js npm/test/unsupported-features.js يمكن باستخدام هذا الخيار البحث أيضًا ضمن المجلد الأب npm لمعرفة الملفات المتعلقة بالمحرك Nashorn المغايرة لملفات الاختبار السابقة كالتالي: $ grep -irL nashorn npm/ يمكنك اختبار الأمر السابق بنفسك ومشاهدة النتيجة، بحيث سيظهر لك نتائج أكثر. 5. تصفية الملفات بأسمائها باستخدام التعابير النمطية كما لاحظنا سابقًا وجود ملفات اختبار متعلقة بالمحرك Nashorn ضمن ملفات المشروع، وبما أن محرك Nashorn مكتوب في لغة جافا، فيمكننا استكشاف ملفات جافا المصدرية ضمن المشروع التي تحوي ذكرًا صريحًا لاسم المحرك، وهناك طريقتين لتنفيذ ذلك بحسب إصدار grep المستخدَم، الطريقة الأولى باستخدام grep للعثور على الملفات التي تحوي النمط "nashorn" ثم تمرير نتيجة الأمر الأول إلى أمر grep آخر يُصفي ملفات جافا فقط كالتالي: $ grep -ir nashorn ./ | grep "^[^:]*\.java" ./spec/nashorn/AsciidoctorConvertWithNashorn.java:public class AsciidoctorConvertWithNashorn { ./spec/nashorn/AsciidoctorConvertWithNashorn.java: ScriptEngine engine = engineManager.getEngineByName("nashorn"); ./spec/nashorn/AsciidoctorConvertWithNashorn.java: engine.eval(new FileReader("./spec/nashorn/asciidoctor-convert.js")); ./spec/nashorn/BasicJavascriptWithNashorn.java:public class BasicJavascriptWithNashorn { ./spec/nashorn/BasicJavascriptWithNashorn.java: ScriptEngine engine = engineManager.getEngineByName("nashorn"); ./spec/nashorn/BasicJavascriptWithNashorn.java: engine.eval(new FileReader("./spec/nashorn/basic.js")); النصف الأول من الأمر تم شرحه مسبقًا، سنشرح القسم الثاني من الأمر وهو "^[\^:]*\.java"، حيث يعتبر الأمر grep افتراضيًا نمط البحث المٌمرر له تعبيرًا نمطيًا، إلا إذا استخدمنا الخيار -F، مما يعني إضافةً لذكر نص صريح لمطابقته حرفيًا، يمكن استخدام محارف وصفية خاصة بالتعابير النمطية للتعبير عن أنماط بحث أعقد، فالنمط المستخدم في مثالنا تُعبر أقسامه عن التالي: ^ بداية سطر [^:]* متبوعة بسلسلة من المحارف لا تحوي على النقطتين (":"). \. متبوعة بنقطة، ولأن النقطة تملك معنى مميز في التعابير النمطية يجب حمايتها باستخدام خط مائل عكسي، مما يعني مطابقة النقطة حرفيًا. java متبوعة بكلمة java. بما أن grep يفصل بين اسم الملف وسياق نتيجة البحث بمحرف النقطتين (":")، يمكننا الاستفادة من ذلك وإبقاء أسماء الملفات التي تنتهي بالامتداد.java فقط في قسم اسم الملف، ويجب الانتباه إلى أن ذلك النمط سيُطابق أيضًا الملفات ذات الامتداد .javascript، يمكنك محاولة حل تلك المشكلة بنفسك إن أردت. 6. تصفية الملفات بأسمائها باستخدام grep التعابير النمطية قوية جدًا، لكن مثالنا بسيط ولا يحتاج لكل هذا التعقيد، في المثال السابق بحثنا في جميع الملفات عن النمط "nashorn" وتجاهلنا العديد من النتائج بعد تمريرها للقسم الثاني من الأمر، يوجد حل لتلك المشكلة في إصدار جنو GNU من الأمر grep الذي يكون مثبتًا عادةً ضمن أنظمة لينكس، وهو باستخدام الخيار --include الذي يوجّه الأمر grep للبحث ضمن الملفات التي تتطابق أسمائها مع نمط glob الممرر فقط: $ grep -ir nashorn ./ --include='*.java' ./spec/nashorn/AsciidoctorConvertWithNashorn.java:public class AsciidoctorConvertWithNashorn { ./spec/nashorn/AsciidoctorConvertWithNashorn.java: ScriptEngine engine = engineManager.getEngineByName("nashorn"); ./spec/nashorn/AsciidoctorConvertWithNashorn.java: engine.eval(new FileReader("./spec/nashorn/asciidoctor-convert.js")); ./spec/nashorn/BasicJavascriptWithNashorn.java:public class BasicJavascriptWithNashorn { ./spec/nashorn/BasicJavascriptWithNashorn.java: ScriptEngine engine = engineManager.getEngineByName("nashorn"); ./spec/nashorn/BasicJavascriptWithNashorn.java: engine.eval(new FileReader("./spec/nashorn/basic.js")); 7. البحث عن كلمات استُخدم في مشروع Asciidoctor.js عدة لغات برمجة أساسها لغة روبي، ولاستخدامه في جافاسكريبت يجب أن يُصرّف باستخدام Opal، وهو مُصرّف مصدر إلى مصدر من روبي إلى جافاسكريبت، يمكننا محاولة فهم الواجهة البرمجية API الخاصة بـ Opal، عبر البحث عن كل ذكر للكائن العام Opal ضمن ملفات جافاسكريبت في المشروع، قد يورد ذكر الكائن ضمن عبارة إسناد (Opal =) أو ضمن عبارة وصول للخواص الأعضاء ضمن الكائن (Opal.) أو ضمن سياق آخر، حيث يمكن استخدام التعابير النمطية للبحث عن ذلك، لكن الأمر grep يوفّر حلولًا أخف من ذلك لمثل تلك المشكلات الشائعة، فباستخدام الخيار -w سيتم مطابقة الكلمات فقط التي تُعرّف تقنيًا بأنها أنماط مسبوقة ومتبوعة بغير محارف الكلمات، تلك المحارف تكون إما محرف بداية السطر أو نهاية السطر أو أي محرف آخر ليس بحرف أو رقم أو شرطة سفلية: $ grep -irw --include='*.js' Opal . ... 8. تلوين الخرج لم ننسخ خرج الأمر السابق لوجود الكثير من النتائج، لكن يمكن تحسين الخرج الكثيف مثل هذا بتلوينه لتسهيل فهمه، في حال لم تكن هذه الميزة مُفعلة افتراضيًا على نظام التشغيل، يمكننا تفعيلها يدويًا لخرج الأمر الحالي بتمرير خيار جنو --color كالتالي: $ grep -irw --color=auto --include='*.js' Opal . ... سيظهر نفس خرج الأمر السابق، لكن مع تلوين عبارة البحث ضمن النتيجة. 9. استخراج عدد الأسطر أو الملفات ضمن البحث يمكننا معرفة طول نتيجة الأمر السابق الذي لم نعرضه كالتالي: $ grep -irw --include='*.js' Opal . | wc -l 86 ما يعني أن لدينا 86 سطرًا يُطابق عبارة البحث ضمن كل الملفات التي جرى البحث ضمنها، يمكننا أيضًا معرفة عدد تلك الملفات التي استخرجت منها النتائج، يمكن باستخدام الخيار -l تحديد خرج الأمر grep بحيث يعرض لنا أسماء الملفات التي احتوت على نتيجة فقط بدلًا من أسطر النتائج، يمكننا بذلك معرفة عدد تلك الملفات كالتالي: $ grep -irwl --include='*.js' Opal . | wc -l 20 قد يذكرنا هذا الخيار بالخيار -L بحرف كبير، حيث تدل عادة الأحرف الكبيرة والصغيرة للخيارات على خيارات متضادة، فيُظهر لنا الخيار -l أسماء الملفات المطابقة للبحث، بينما يظهر الخيار -L الملفات الغير مطابقة للبحث، لمثال آخر على ذلك يمكنك الرجوع إلى الدليل والتحقق من الفرق بين الخيارين -h و -H، وبالعودة لنتيجة بحثنا حصلنا على نتيجتين هما مطابقة 86 سطرًا، و 20 مِلفًا، يمكننا أيضًا معرفة طبيعة توزع تلك الأسطر ضمن تلك الملفات، فباستخدام الخيار -c للأمر grep سيتم عد الأسطر المُطابقة ضمن كل ملف على حدى، بما فيها الملفات التي لا تحوي على نتائج: $ grep -irwc --include='*.js' Opal . ... يحتاج خرج الأمر السابق لمعالجة لاستخراج المعلومات المطلوبة، لأن ترتيب النتائج ضمنه تكون بحسب ترتيب معالجة الملفات، ويتضمن أيضًا الملفات التي لا تحوي على نتائج وهو ما لا يهمنا في هذه الحالة، يمكن حل المشكلة الأخيرة بسهولة عبر تصفية الملفات التي تحوي 0 نتائج كالتالي: $ grep -irwc --include='*.js' Opal . | grep -v ':0$' ولترتيب النتائج يمكننا تمرير النتيجة النهائية إلى أمر الترتيب sort كالتالي: $ grep -irwc --include='*.js' Opal . | grep -v ':0$' | sort -t: -k2n يمكنك الرجوع إلى دليل الأمر sort لمعرفة معاني الخيارات التي استخدمناها في المثال السابق. 10. إيجاد الفرق بين نتيجتي بحث استخدمنا في أحد الأمثلة السابقة الكلمة ".Opal"، في حال بحثنا في نفس تلك الملفات هذه المرة عن الكلمة "Opal," سنحصل على عشرين نتيجة إضافية: $ grep -irw --include='*.js' Opal . | wc -l 86 $ grep -ir --include='*.js' Opal . | wc -l 105 يمكننا استخراج الفرق بين عمليتي البحث، وما هي الأسطر التي تحتوي على أحرف كلمة opal الأربعة متفرقة من دون أن تشكل كلمة واحدة؟، فمن الصعب الإجابة على هذا السؤال لأنه يمكن لنفس السطر أن يحوي كلًا من كلمة opal وكلمة أكبر منها تحوي حروفها الأربعة، يمكن محاولة الإجابة على هذا السؤال مبدأيًا بتمرير النتيجة إلى أمر آخر كما فعلنا في مثال سابق: $ grep -ir --include='*.js' Opal . | grep -ivw Opal ./npm/examples.js: const opalBuilder = OpalBuilder.create(); ./npm/examples.js: opalBuilder.appendPaths('build/asciidoctor/lib'); ./npm/examples.js: opalBuilder.appendPaths('lib'); ... يمكنك أيضًا محاولة البحث واستكشاف استخدامات الكائن opalBuilder بنفسك. ختامًا تنفيذك لعدد من أوامر grep ضمن مشروع جديد لن يمكنك من فهم ترتيب ومعمارية المشروع وبنية الشيفرات ضمنه، ولكن ستتمكن من إجراء تحليلات بسيطة مشابهة للأمثلة التي ذكرناها تفيدك في التعرف على المشاريع الجديدة، رأينا قوة الأمر grep واستخداماته المتعددة التي يمكنك إضافتها إلى مهاراتك. ترجمة -وبتصرف- للمقال 10 Practical Grep Command Examples for Developers لصاحبه Sylvain Leroux. اقرأ أيضًا دليل استخدام الأمر grep في لينكس ما الفروق بين الأوامر grep و egrep fgrep البحث ضمن جميع الملفات والمجلدات في لينكس باستخدام الأداة Grep تعلم استخدام الأمر rg بديل grep المحسن في لينكس
-
تعد Grep الأداة الأفضل للبحث ضمن محتوى الملفات في نظام التشغيل لينكس، حيث لها استخدامات عديدة، ومن أشيع تلك الاستخدامات هو البحث ضمن ملف ما عن مصطلح، بالصيغة التالية: grep search_term filename وللبحث ضمن جميع الملفات ضمن مجلد ما يمكن تنفيذ الأمر كالتالي: grep search_term * المشكلة هنا أن عملية البحث ستتم على الملفات ضمن المجلد الحالي فقط، ولن يتم البحث ضمن المجلدات الفرعية له، يمكن حل تلك المشكلة بإجبار البحث ضمن كل الملفات وكل المجلدات الفرعية تكراريًا باستخدام الخيار r- كالتالي: grep -r search_term . يمكن ذكر اسم المجلد المراد البحث ضمنه بشكل صريح أيضًا في حال لم يكن هو المجلد الحالي كالتالي: grep -r search_term directory_path سنوضح استخدامات grep من خلال أمثلة عملية ضمن الفقرة التالية. البحث ضمن جميع ملفات مجلد ما يوضح خرج الأمر tree التالي بنية الملفات والمجلدات التي سنطبق عليها الأمثلة في هذا المقال، بحيث تحوي جميع الملفات الموضحة عبارة "simple"، فيما عدا الملف empty.txt فهو فارغ: abhishek@LHB:~/scripts$ tree . ├── dir1 │ └── new_script.sh ├── dir2 │ └── your_script.sh ├── dir3 │ ├── empty.txt │ └── linked.txt -> ../../sample.txt ├── my_script.sh └── your_script.sh 3 directories, 6 files يمكننا استخدام محرف البدل ("*") للبحث عن الكلمة "simple" ضمن جميع الملفات داخل المجلد الحالي، بحيث سيُبدّل محرف البدل بأسماء جميع الملفات والمجلدات داخل المجلد الحالي: grep simple * الأمر السابق سيُنفذ عملية البحث ضمن جميع الملفات ضمن المجلد الحالي، ولن يدخل إلى مجلداتها الفرعية، وبما أن البحث سيطبق فقط على الملفات، فسيظهر لنا رسالة بالصيغة التالية "XYZ is a directory" تدل على تجاهل المجلدات بنفسها. في حال لم يكن المجلد الحالي هو ما نريد البحث ضمنه، يمكن ذكر مسار المجلد المطلوب منتهيًا باللاحقة "*/" كالتالي: grep search_term directory_path/* هنا استخدمنا محرف البدل في النهاية لتوسيع العناصر المستهدفة سواء كانت ملفات أو مجلدات ضمن المجلد المحدد، وبالاعتماد على ما سبق سنرى في الفقرة القادمة كيف يمكن تنفيذ بحث تكراري يدخل إلى كافة الملفات ضمن المجلدات الفرعية. البحث التكراري ضمن جميع المجلدات الفرعية لمجلد يمكن استخدام الخيار r- لتفعيل البحث التكراري، بحيث سينظر grep داخل جميع الملفات ضمن المجلد المستهدف وداخل جميع الملفات ضمن المجلدات الفرعية داخله أيضًا، المثال التالي يشابه مثال البحث في الفقرة السابقة لكن مع إضافة البحث التكراري، سنلاحظ ظهور نتائج من ملفات داخل المجلدات الفرعية أيضًا: grep -r simple . خرج تنفيذ الأمر السابق: يوجد أيضًا الخيار R- لتنفيذ البحث التكراري، وهو يعمل بشكل مطابق للخيار r-: grep -R simple . الفرق الوحيد بين الخيارين هو أن الخيار R- خيار بحث بإلغاء المرجعية، يعني أنه يقوم باتباع الوصلات الرمزية إلى ملفها الأصلي الموجود في مكان آخر، ويوضح المثال التالي استخدام الخيار R-: نلاحظ الفرق في نتيجة البحث حيث ظهرت نتيجة ضمن ملف الوصلة الرمزية linked.txt، ولم يظهر لنا ضمن النتائج عند استخدام الخيار r- سابقًا، في حال لم نكن ضمن المجلد المراد البحث ضمنه يمكن ذكر المسار النسبي أو المطلق للمجلد المطلوب كالتالي: grep -r search_term path_to_directory استثناء مجلد من عملية البحث التكراري يمكن توجيه grep لاستثناء البحث ضمن مجلد فرعي ما عند تنفيذ عملية البحث التكراري باستخدام الخيار exclude-dir-- كالتالي: grep -r --exclude-dir=dir_name serach_term directory_path يمكننا أيضًا استثناء عدة مجلدات فرعية من البحث التكراري باستخدام الخيار السابق بالصيغة التالية: grep -r --exclude-dir={dir1,dir2} serach_term directory_path وبتطبيق ذلك على مثالنا سيظهر الخرج التالي: بحيث يعمل خيار الاستثناء مع كلًّا من خياري البحث التكراري r- و R-. الخلاصة الجدول التالي يتضمن خلاصة استخدامات grep للبحث ضمن كل الملفات والمجلدات، والتي شرحناها ضمن هذا المقال: table { width: 100%; } thead { vertical-align: middle; text-align: center; } td, th { border: 1px solid #dddddd; text-align: right; padding: 8px; text-align: inherit; } tr:nth-child(even) { background-color: #dddddd; } أمر Grep الوصف grep string * البحث ضمن كل الملفات ضمن المجلد الحالي grep string dir البحث ضمن كل الملفات ضمن المجلد dir grep -r string . البحث التكراري ضمن كل الملفات داخل المجلدات الفرعية grep -r string dir البحث التكراري ضمن كل الملفات داخل المجلدات الفرعية ضمن المجلد dir grep -R string . مثل الخيار r- لكن يتبع الوصلات الرمزية ترجمة -وبتصرف- للمقال How to Perform Grep Search on All Files and in All Directories لصاحبه Abhishek Prakash. اقرأ أيضًا دليل استخدام الأمر grep في لينكس ما الفروق بين الأوامر grep وegrep fgrep تعلم استخدام الأمر rg بديل grep المحسن في لينكس
-
طوُّرت أداة ripgrep نتيجةً لجهود مطوري البرامج مفتوحة المصدر ضمن حملة لإعادة كتابة البرامج بلغة رست Rust كبديل أقوى عن الأداة المعروفة grep،صيغة استخدامها كالتالي: rg [files/folders] <pattern> مع استبدال files/folders بأسماء الملفات أو المجلدات المُراد البحث ضمنها، وهو معامل اختياري، واستبدال pattern بنمط البحث الذي نحاول العثور على نتائج تطابقه. نلاحظ وخلافًا للأمر grep، أن ذكر اسم ملف ليتم البحث ضمنه هو اختياري وغير ضروري، فعند عدم تمرير اسم ملف معين سيُبحث ضمن جميع الملفات، تفيد تلك الميزة عند نسيان أيّ من الملفات يحوي النمط الذي نبحث عنه، وهي طريقة أبسط بمقارنتها بتنفيذ نفس العملية باستخدام grep. ما هي أداة ripgrep؟ هي أداة مُطابقة أنماط قياسية متكررة تأخذ بالحسبان ملفات gitignore. في حال وجود ذكر لملفات معينة أو لواحق أو مجلدات ضمن ملف gitignore. ستتجاهلها الأداة ripgrep، مما يُسرّع زمن تنفيذ عملية البحث، ومن مزايا أداة ripgrep: البحث عن الأنماط تكراريًا ضمن المجلدات. تلوين المُطابقات ضمن الخرج. دعم للعديد من صيغ الترميز مثل UTF-8 و SHIFT_JIS. القدرة على البحث ضمن الملفات المضغوطة zip. تجاهل الملفات المخفية افتراضيًا، والملفات المطابقة للأنماط ضمن ملف gitignore لتسريع عملية البحث. فهي أداة مشابهة تمامًا لأداة grep، لكنها موجهة للبحث ضمن محتوى الملفات بدلًا من البحث ضمن مجرى من البايتات. تثبيت ripgrep لا تأتي أداة ripgrep مثبتة مسبقًا ضمن نظام التشغيل كما هو الحال مع grep، ولكنها متاحة ضمن كافة المستودعات ضمن توزيعات لينكس الشهيرة، بحيث يمكن تثبيتها باستخدام مدير الحزم، فضمن توزيعة لينكس Arch يمكن تثبيتها بتنفيذ الأمر التالي: pacman -S ripgrep وضمن جينتو Gentoo باستخدام الأمر: emerge sys-apps/ripgrep وعلى توزيعات فيدورا وريد هات بتنفيذ الأمر التالي: sudo dnf install ripgrep وضمن توزيعة أوبن سوزي إصدار 15.1 وما فوق بتنفيذ الأمر: sudo zypper install ripgrep وضمن توزيعة ديبيان Buster الإصدار 10 وما فوق باستخدام apt، ويمكن ضمن توزيعة أوبنتو Cosmic Cuttlefish إصدار 18.10 وما فوق تحميلها من المستودعات الرسمية للتوزيعة، باستخدام الأمر: sudo apt install ripgrep استخدام الأمر ripgrep ستجد استخدام الأمر سهلًا في حال لديك خبرة سابقة باستخدام الأمر grep، بحيث نمرر له نص البحث واسم ملف، ليبحث بعدها ضمنه ويعرض لنا أماكن تطابق نص البحث مع المحتوى داخل الملف، الأمثلة ضمن هذا المقال نُفذت ضمن نسخة من مجلد مستودع الأداة dust. عمليات البحث البسيطة المثال التالي يبحث عن النص description ضمن محتوى الملف Cargo.html: $ rg description Cargo.toml 3:description = "A more intuitive version of du" 53:extended-description = """\ فبعد تنفيذ الأمر بحثت لنا الأداة ضمن الملف المذكور وعرضت الأسطر مع أرقامها التي حَوت مُطابقة مع نص البحث: عند تمرير أسماء لعدة ملفات للبحث ضمنها، أو عند عدم تمرير أسماء ملفات ما يعني البحث ضمن جميع الملفات، سيظهر ضمن الخرج أسماء الملفات التي عُثر ضمنها على مطابقات: يمكن الاستفادة من استخدام الخيار file-- للإشارة إلى ملف يحوي أكثر من نمط ليتم البحث عنها، قد نحتاج ذلك في حال كنا نكرر البحث عن عدة أنماط دومًا: إظهار نتيجة البحث ضمن السياق من المفيد والضروري أحيانًا عرض السياق الذي عُثر ضمنه على النتيجة، خصوصًا عند بحثنا ضمن مستودع أو ملفات تحوي شيفرات، نستفيد من الخيار C- أو context-- لتمرير عدد يدل على عدد الأسطر التي نريد إظهارها قبل وبعد النتيجة: نحتاج أحيانًا لعرض سطر النتيجة وما فوقه، ونحتاج أحيانًا أخرى لعرض سطر النتيجة وما بعده فقط، يمكن الاستفادة من الخيار A- أو after-context-- وتمرير عدد الأسطر الواجب إظهارها أسفل كل نتيجة: ولإظهار الأسطر فوق النتيجة يمكن الاستفادة من الخيار B- أو before-context-- وتمرير عدد الأسطر الواجب إظهارها فوق كل نتيجة: الأعمدة يوفر ripgrep عدة خيارات تخص الأعمدة، منها الخيار column-- لطباعة إحداثيات مكان النتيجة بالصيغة "رقم السطر:رقم العمود" في بداية سطر كل نتيجة، ما يفيدنا في حال استخدامنا لمحرر نصوص مثل vim: يوجد أيضًا الخيار M- أو max-columns-- الذي يأخذ قيمة عددية تمثل عدد الأعمدة ضمن الخرج، وفي حال تجاوزت نتيجة ما في أعمدتها ذلك العدد، يتم تجاهل عرضها والاكتفاء بعرض رسالة توضيحية تعبر عن النتيجة: خيارات أخرى يوجد العديد من الخيارات الممكن استخدامها مع الأمر ripgrep، مثلًا يمكن استخدام الخيار s- أو case-sensitive-- لجعل عملية المطابقة حساسة لحالة الأحرف: وإذا أردنا إظهار كل النتائج وتجاهل حالة الأحرف يمكن استخدام الخيار i- أو ignore-case--: يمكن استخدام عدة مسالك Threads معًا لتنفيذ عملية البحث، حيث يفيد ذلك عند البحث ضمن كمية كبيرة من الملفات، كمستودع كبير للشيفرة المصدرية، يمكن تحديد عدد المسالك المستخدمة في عملية البحث بتمرير عدد للخيار j- أو threads--: $ rg -j 4 TODO لعكس نتيجة البحث أي استثناء نمط ما من نتائج البحث، يمكن استخدام الخيار v- أو invert-match--. يمكن للأداة ripgrep البحث ضمن الملفات النصية المٌحتواه داخل ملف أرشيف مضغوط باستخدام الخيار z- أو search-zip-- عادة يستخدم ذلك الخيار مع الخيار a- لمعاملة الملفات الثنائية على أنها ملفات نصية: في الختام يمكن الاستفادة من الأداة ripgrep بشكل كبير، وخاصة لو كنت مبرمجًا تعمل على أنظمة تشغيل ببيئات شبيهة بيونكس، مع أنها لا تعتبر بديلًا عن الأداة grep لأن وظيفتها مختلفة، حيث لكل منهما استخداماته وتطبيقاته المفيدة. ترجمة -وبتصرف- للمقال Using ripgrep (rg) Command in Linux لفريق الموقع. اقرأ أيضًا دليل استخدام الأمر grep في لينكس ما الفروق بين الأوامر grep وegrep fgrep الدليل النهائي لاختيار توزيعة لينكس
-
تعلم مبادئ البحث عن المعلومات في ملفاتك، ثم حمّل الورقة المرجعية التي نقدمها لك لتحصل على دليل مرجعي سريع للأمر grep والتعبيرات النمطية regular expression المرتبطة به. إن الأمر grep هو اختصار لعبارة طباعة التعبير النمطي العالمي Global Regular Expression Print، هو أحد أوامر نظام يونكس Unix التقليدية، طوَّره كِن طومسون Ken Thompson في عام 1974. إنه واسع الانتشار في مجال الحوسبة لدرجة أنه يستخدَم كثيرًا كفعل بمعنى "يبحث" باللغة الإنجليزية (بشكل مشابهة للفعل google الذي يأتي بمعنى البحث في الإنترنت). بالمختصر إن grep هو وسيلة بحث في أي ملف عن نمط محدد من المحارف. إذا ذكرك هذا الأمر بخيار البحث Find الحديث والمتاح في أي معالج نصوص أو محرر نصوص، هذا يعني أنك لحظت فعلًا نتائج هذا الأمر في مجال الحوسبة. إن الأمر grep بعيد كل البعد عن أن يكون أمرًا قديمًا عتيق الطراز استبدلته التكنولوجيا الحديثة، إذ تكمن قوته الحقيقية في عاملَين: يعمل الأمر grep على الطرفية وينفَّذ على تدفقات البيانات، لذا يمكنك إدراجه في العمليات المعقدة. فهو لا يتيح لك إيجاد كلمة في ملف نصي فحسب، بل تستطيع استخراج الكلمة وتضمينها في أمر آخر أيضًا، وهكذا. يستخدم grep التعبيرات النمطية regular expression ليضفي مرونةً على عملية البحث. من السهل تعلم استخدام الأمر grep، رغم أنه يحتاج إلى بعض الممارسة. سنتناول في هذه المقالة بعض أنفع خصائصه. تثبيت grep ستجد grep مثبَّتًا مسبقًا إذا كان نظام التشغيل لديك لينكس. أما إذا كان نظام التشغيل لديك ماك او إس macOS سيكون لديك إصدار grep الخاص بنظام تشغيل BSD، الذي يختلف اختلافًا بسيطًا عن الإصدار الخاص بنظام GNU، لذا إذا أردت المتابعة معنا في هذه المقالة بدقة ثبِّت grep الخاص بالإصدار GNU من مشاريع مثل Homebrew أو MacPorts. أساسيات الأمر grep لا تتغير صيغة الأمر grep الأساسية إذ تكتب الأمر grep ثم ترفقه بنمط محدد ثم اسم الملف الذي تريده أن يبحث ضمنه، في المقابل يطبع الأمر كل سطر يحتوي ما يطابق النمط الذي أدخلته على الطرفية. $ grep gnu gpl-3.0.txt along with this program. If not, see <http://www.gnu.org/licenses/>. <http://www.gnu.org/licenses/>. <http://www.gnu.org/philosophy/why-not-lgpl.html>. يكون الأمر grep افتراضيًا حساسًا لحالة الأحرف case-sensitive، لذا تختلف كتابة "gnu" عن "GNU" أو "Gnu". يمكنك جعله يتجاهل حالة الأحرف بإضافة خيار ignore-case--. $ grep --ignore-case gnu gpl-3.0.txt GNU GENERAL PUBLIC LICENSE The GNU General Public License is a free, copyleft license for the GNU General Public License is intended to guarantee your freedom to GNU General Public License for most of our software; it applies also to [...16 more results...] <http://www.gnu.org/licenses/>. <http://www.gnu.org/philosophy/why-not-lgpl.html>. إذا أردت أن يعيد الأمر grep جميع الأسطر التي لا تحتوي تطابقًا مع النمط الذي أدخلته، استخدم الخيار invert-match--: $ grep --invert-match \ --ignore-case gnu gpl-3.0.txt Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> [...648 lines...] Public License instead of this License. But first, please read الأنابيب Pipes من المفيد أن تستطيع إيجاد نص تبحث عنه ضمن ملف، لكن تكمن القوة الحقيقة للبرامج المتوافقة مع معايير POSIX في قدرتها على ربط الأوامر معًا من خلال "الأنابيب pipes". فقد وجدت أن أفضل وسيلة لاستخدام الأمر grep تكون عند جمعه مع أدوات أخرى مثل cut أو tr أو curl. فمثلًا، لنفترض أنه لدي ملف يعرض بعض الأوراق الفنية التي أريد تنزيلها. يمكنني فتح الملف والضغط يدويًا على كل رابط، ثم تحديد موقع حفظ كل ملف ليكون على قرص الصلب الخاص بي من خيارات متصفح فايرفوكس Firefox، لكن هذا سيستغرق وقتًا طويلًا وجهدًا كبيرًا. أو يمكنني استخدام الأمر grep للبحث عن الروابط ضمن الملف، وطباعة سلسلة المحارف المطابقة فقط من خلال استخدام خيار only-matching--: $ grep --only-matching http\:\/\/.*pdf example.html http://example.com/linux_whitepaper.pdf http://example.com/bsd_whitepaper.pdf http://example.com/important_security_topic.pdf سيكون الخرج عبارةً عن قائمة روابط، يعرَض كل رابط منها على سطر. هذا يوافق طريقة معالجة باش Bash للبيانات. وبدلًا من أن تطبَع الروابط على الطرفية يمكنني إضافة أنبوب لهم ليكونوا مباشرةً دخلًا للأمر curl: $ grep --only-matching http\:\/\/.*pdf \ example.html | curl --remote-name ستكون النتجة أنه سيحمَّل كل ملف ويحفَظه بنفس اسم الملف المنزَّل على القرص الصلب. قد يبدو النمط الذي أدخلته للبحث مشفرًا، هذا لأنني استخدمت التعبيرات النمطية regular expression، وهي نوع من لغة "محارف البدل" wildcard التي تبرز فائدتها عند البحث الواسع بين كم كبير من النصوص. التعبيرات النمطية يعلم الجميع مدى صعوبة التعبيرات النمطية regular expression (التي تسمى اختصارًا regex)، لكنها ليست بالصعوبة التي يشاع عنها أيضًا. صحيح أن بعض الأشخاص قد يبالغون في تعقيد كتابة التعبيرات النمطية لدرجة تصبح فيها غير مقروءة، ويوسعونها لدرجة تضعِف فاعليتها، لكن ليس عليك أن تبالغ في كتابة تعبيرك النمطي. سأستعرض لك تعريفًا موجزًا عن التعبيرات النمطية حسب أسلوبي في استخدامها. ابدأ بإنشاء ملف وسمّه example.txt وأدخل المحتوى النصي التالي فيه: Albania Algeria Canada 0 1 3 11 أبسط عنصر في التعبيرات النمطية هو محرف .، الذي يمثل محرفًا واحدًا. $ grep Can.da example.txt Canada استطعنا باستخدام النمط Can.da الحصول على كلمة Canada لأن المحرف . يمثل أي محرف واحد فقط. تمكنك الرموز التالية من تعديل محرف البدل . ليمثل أكثر من محرف واحد فقط. ? : لا تطابق العنصر الذي يسبقها ولا مرة، أو تطابقه مرةً واحدةً فقط. * : لا تطابق العنصر الذي يسبقها ولا مرة، أو تطابقه عدة مرات. + : تطابق العنصر الذي يسبقها مرةً واحدةً أو أكثر {4} : تطابق العنصر الذي يسبقها 4 مرات (يكون عدد المرات حسب الرقم الذي تدخله ضمن القوسين). تسلح بهذه المعرفة وابدأ التدرب على ملف example.txt ولنرى التركيبات التي ستبتكرها. ستصيب في بعضها وستخطئ في الآخر، لكن ما يهم فعلًا هو أن تحلل النتائج التي تحصل عليها لتفهم سبب الإصابة أو الخطأ. لتستخدم التعبيرات النمطية المتقدمة عليك إضافة الخيار extended-regexp-- أو E-. مثلًا، لن يعيد إليك الأمر التالي اسم أية مدينة: $ grep -E A.a example.txt أخفقت لأن المحرف . لا يطابق إلا حرفًا واحدًا فقط إذا لم ترقّيه. تستطيع فعل ذلك باستخدام المحرف * مثلًا، إذ أنك تملي عند ذلك على الأمر grep أن لا يطابق حرفًا واحدًا أبدًا أو يطابقه عدة مرات حتى يصل إلى نهاية الكلمة. ولمعرفتك بمحتوى القائمة التي تجرب الأمر عليها تعلم أنه في مثالك هذا لا توجد حالة لن يطابق فيها الحرف الوحيد الذي يسبقه ولا مرة حتى، لأنه لا يوجد اسم أية دولة يتألف من 3 أحرف فقط في هذه القائمة. لذا يستحسن أن تستخدم + ليطابق حرفًا واحدًا على الأقل أو يطابقه عدة مرات حتى يصل إلى نهاية الكلمة: $ grep -E A.+a example.txt Albania Algeria إذا أردت أن تدخل سلسلة أحرف استخدم الأقواس المعقوفة: $ grep -E [AC].+a example.txt Albania Algeria Canada يفيد هذا في حال كنت تبحث عن أرقام أيضًا، ستفاجئك النتائج التي سترد كالمثال التالي: $ grep [1-9] example.txt 1 3 11 هل فاجأتك رؤية الرقم 11 في بحثك عن الأرقام من 1 إلى 9؟ مالذي سيحدث عندما تضيف الرقم 13 إلى القائمة؟ هل ستظهر في النتيجة أيضًا؟ ظهرت هذه الأرقام لأنها تحتوي على الرقم 1، وهو ضمن قائمة الأرقام التي حددتها. وكما ترى، إن التعبيرات النمطية كالأحجية، لكن من خلال التجربة والتمرين ستألَف استخدامها في بحثك في البيانات باستخدام الأمر grep. ترجمة -وبتصرف- للمقال How to use the Linux grep command لصاحبه Seth Kenlon. اقرأ أيضًا المدخل الشامل لتعلم علوم الحاسوب ما الفروق بين الأوامر grep وegrep fgrep إدارة العمليات (Process) في لينكس باستخدام الطرفية مقدمة إلى أذونات لينكس Linux Permissions احترف الأمر ls في لينكس
-
تشتهر أداة grep بكونها إحدى أدوات البحث الأكثر شهرة في الأنظمة الشبيهة بيونكس Unix-like، سواء تعلّق الأمر بالبحث عن ملفات، سطر أو أسطر عدّة ضمن ملفّ، فهي سريعة وتدعم الكثير من الخيارات مثل: البحث حسب نمط Pattern مكوَّن من سلسلة محارف String والبحث اعتمادًا على تعابير نمطية Regular expressions، بما في ذلك تعابير Perl النمطية Perl reg-ex. تتوفّر grep، نظرا لتعدّد وظائفها، على عدّة تنويعات تشمل rgrep، pgrep،fgrep، egrep وغيرها. توجد اختلافات يسيرة بين هذه التنويعات تجعل المبرمجين يستخدمون كلّ تنويعة لمهامّ محدّدة حسب رغبتهم وتفضيلهم. سنعرض في هذا المقال للاختلفات الأساسية بين التنويعات الثلاثة الأكثر شهرة، وهي egrep، grep وfgrep، ومالمتطلبات التي تجعل مستخدمي لينكس يختارون إحداها بدلا من الأخرى. سنستخدم ملفا بالمحتوى التالي ونسمّيه check_file لتطبيق الأوامر في هذا الدرس عليه. grep is a command that can be used on unix-like systems. it searches for any string in list of strings or file. It is very fast. (f|g)ile ملحوظة: لتوافق نتائج تنفيذ الأوامر لديك النتائج المعروضة في هذا الدرس، يجب أن يكون محتوى الملف مطابقا للمحتوى أعلاه: حالة الأحرف +(كبيرة أو صغيرة) وبداية الأسطر. تأكّد كذلك من تنفيذ الأوامر من المجلّد الذي يوجد به الملف، أو اكتب مسار الملف كاملا. الأمر grep يعدّ أمر grep الأمر الأساسي في الأنظمة الشبيهة بيونكس للبحث عن مجموعة محارف مهما كان نوعها ضمن سلسلة محارف، ملف، مجموعة ملفات أو ربما نتيجة تنفيذ أمر آخر. يستخدم الأمر grep التعابير النمطية القاعدية Basic Regular Expressions, BRE في البحث؛ علاوة على سلاسل المحارف الاعتيادية. تفقد المحارف الوصفية Meta characters عند استخدام التعابير النمطية القاعدية قدرتها التعبيرية، ويُتَعامل معها كأي محرف عادي؛ إلا إذا سُبِقت بمحرف تخليص Escape (وهو المحرف \). نرصُد في ما يلي أهم المحارف الوصفية بالنسبة للأمر grep. +: يعني عند تخليصه أننا نبحث عن السلاسل التي يتكرّر فيها المحرف قبله (على يساره) لمرة واحدة على الأقل. يمكن أن توافق العبارةُ a+b سلاسل المحارف ab، aabcd،aaab وaaaab، إلا أنها لا توافق العبارة bcd. ?: يشير إلى تكرار المحرف الذي قبله لمرة واحدة على الأكثر، حسب طريقة الاستخدام. (: يشير إلى بدء عبارة تناوب Alternation؛ أي موافقة أحد خيارات يفصل بينها الخط العمودي |. ): يشير إلى نهاية عبارة تناوب Alternation. |: يفصل بين الخيارات ضمن عبارة تناوب. يعني التعبير النمطي التالي (a|b)cde “الحرف a أو الحرف b تتبعه الأحرف cde بهذا الترتيب”؛ أي أن العبارتيْن acde وbcde توافقان التعبير النمطي المذكور. {: يشير هذا المحرف إلى بداية محدّدِ مجال. }: يشير هذا المحرف إلى نهاية محدّد مجال. مثلا؛ تعني العبارة التالية a{2} أننا نبحث عن الحرف a مكررا مرتيْن. راجع مقال مقدّمة في التعابير النمطية للمزيد عن هذه الدلالات واستخداماتها. ننفّذ الأمر grep بالطريقتيْن التاليتيْن: grep '(f|g)ile' check_file grep '\(f|g\)ile' check_file نلاحظ الفرق في النتيجة: يبحث الأمر الأول في الملف check_file عن سلسلة المحارف “(f|g)ile” كما كُتِبت دون أن يُفسّر المحارف (، ) و| تفسيرا خاصًّا. ينتُج عن تنفيذ الأمر إظهار الأسطُر التي تحوي سلسلة المحارف المرغوبة، مع عرض السلسلة بلون مغاير؛ حسب الإعدادات (أحمر في حالتي). تبدو النتيجة مغايرة بالنسبة للأمر الثاني الذي وضعنا فيه محرف التخليص \ أمام كل محرف نريد أن يُفسَّر بدلالته الخاصّة (محرف وصفي)، وليس كمحرف متضمَّن في الجملة التي نبحث عنها. تُصبح دلالة التعبير النمطي المُمرَّر إلى grep: “الكلمات التي يوجد بها أحد الحرفيْن f أو g متبوعا بالأحرف ile“. ملحوظة: استخدم الخيار o- إن أردتَ إظهار الكلمة التي تطابق التعبير النمطي لوحدها، دون السطر الذي توجد فيه: grep -o '(f|g)ile' check_file grep -o '\(f|g\)ile' check_file الأمر egrep يشبه اﻷمر egrep الأمرَ grep مع فرق أنه يتعامل مع المحارف الوصفية مباشرةً دون الحاجة لمحرف تخليص؛ بمعنى أنه يأخذها بدلالتها الخاصة مباشرةً. نعيد، لفهم الفكرة جيّدًا، تنفيذَ الأمريْن السابقيْن مع إحلال egrep مكان grep: egrep '(f|g)ile' check_file egrep '\(f|g\)ile' check_file يبدو الأمر هنا معكوسا: بدون تخليص المحارف الوصفية فإن الأمر egrep يحتفظ بدلالتها الخاصّة، فيبحث في الحالة الأولى عن جميع سلاسل المحارف التي تبدأ بحرف f أو g؛ أما في الحالة الثانية فيعدّ المحارف (، ) و| جزءًا من السلسلة ويبحث بالتالي عن العبارة (f|g)ile كما هي. ملحوظة: يشبه تنفيذ الأمر egrep تنفيذَ الأمر grep مع الخيار E-: grep -E '(f|g)ile' check_file grep -E '\(f|g\)ile' check_file يُفضّل كثيرون استخدام egrep بدلا من grep للبحث اعتمادًا على تعابير نمطيّة إذ أنها تزيح عن كاهلهم ضرورة تخليص المحارف الوصفية؛ خصوصا في العبارات النمطية المعقدة. الأمر fgrep لا يتعامل الأمر fgrep مع التعابير النمطية ولا المحارف الخاصّة؛ فالمعطى المُمرَّر له أولا هو سلسلة محارف ينبغي البحث عنها كما هي. يشبه استخدام fgrep استخدام الأمر grep مع فرق أن الأخير سيفسّر المحرف \ على أنه محرف تخليص، بينما لا يتعرف egrep عليه نهائيا؛ فهو بالنسبة له مجرد محرف كالبقية. fgrep '(f|g)ile' check_file fgrep '\(f|g\)ile' check_file تمكن ملاحظة أن fgrep بحث في كلتا الحالتيْن عن سلسلة المحارف كما مُرِّرت إليه. في الحالة الأولى كانت النتيجة مشابهة لتنفيذ الأمر grep بدون تخليص المحارف، وفي الثانية أضفنا محرف التخليص \؛ إلا أن fgrep لا يعدّه محرفا ذا دلالة خاصّة فيبحث عن السلسلة كما كُتبت ولا يجدها في الملف. ملحوظة: يشبه تنفيذ الأمر fgrep تنفيذَ الأمر grep مع الخيار F-: grep -F '(f|g)ile' check_file grep -F '\(f|g\)ile' check_file تعرّفنا في هذا الدرس على الفروق الأساسيّة بين ثلاث تنويعات من الأمر grep شائع الاستخدام في البحث عن سلاسل المحارف. يمكنك اختيار التنويعة التي تناسبك حسب الحاجة. ترجمة بتصرف لمقال What’s Difference Between Grep, Egrep and Fgrep in Linux? لصاحبه Gunjit Khera.