أساسيات جنو grep للمبتدئين
شرح grep والتعابير النمطية regular expression, regex
تعد Grep واحدة من مجموعة أدوات “Swiss Army knife” الخاصة بإدارة النظام، وهي مفيدة للغاية للبحث عن السلاسل والأنماط ( عبارات تحوي حرف أو مجموعة أحرف أو رموز معينة) في مجموعة من الملفات أو حتى المجلدات الفرعية. يقدم هذا المقال أساسيات Grep، ويقدم أمثلة على الاستخدام المتقدم ويربطك بمزيد من الصفحات المتعلقة بهذا الموضوع.
قبل البدء بالشرح يجب أن أشرح بعض المصطلحات هنا حتى نفهم الشرح جيدًا:
-
النمط أو بالإنجليزية pattern كما ذكرت هو مجموعة أحرف أو رموز أو أرقام (أو جميعهم مع بعض)، مثلا عندما أريد البحث عن حرفي “sd” في الملف أو عبارة “.?why” فهذه العبارة نعتبرها نمطًا ﻷننا نبحث في ملف أو مجموعة ملفات عن كل كلمة تحوي هذه العبارة أو هذا الرمز أو الحرف..
-
التعبيرات النمطية أو بالإنجليزية regular expression هي باختصار شديد عبارة يتم كتابتها وفق قواعد معينة لتكون نتائج البحث كما نرغب، يعني مثلا نريد البحث عن كل كلمة تبدأ بحرف “a” وتنتهي بحرف “d”، كما لاحظت فلا يمكن تمثيل هذا الشيئ بالأنماط المذكورة أعلاه ﻷننا لم نحدد الأحرف التي ستكون بين الحرفين “a” و “d” ولهذا نستخدم هنا لهذا الغرض التعبيرات النمطية ويكون شكلها مثلا “$a*d^” حيث يشير الرمز
^
لبداية الكلمة والرمز$
لنهايتها وما إلى ذلك.. -
الهدف الأساسي من الأمر grep هو البحث كما ذكرنا، وتتعامل grep مع التعبيرات النمطية التي شرحتها أعلاه وذلك للبحث المتقدم في الملفات.
لنكمل الآن الشرح..
يتم تثبيت Grep (وهو اختصار لـ “Global Regular Expression Print”) افتراضيًا على كل توزيعة ﻷنظمة Linux و BSD و UNIX، وهو متاح أيضًا لنظام Windows. تقوم GNU ومؤسسة البرمجيات الحرة بتوزيع Grep كجزء من مجموعة أدوات المصادر المفتوحة. يركِّز هذا المقال التعليمي في المقام الأول على إصدار جنو، لأنه الأكثر استخدامًا حاليًا.
يعثر Grep على نمط في ملف أو عبارة مُدخلة من المستخدم بسرعة وكفاءة. على الرغم من أن معظم الاستخدامات اليومية للأمر بسيطة، إلا أن هناك مجموعة متنوعة من الاستخدامات الأكثر تقدّمًا والتي لا يعرفها معظم الأشخاص، بما في ذلك التعبيرات المعتادة والتي قد تصبح معقدة للغاية.
الأداة لها جذورها في بناء جملة التعبيرات النمطية (regular expression) الموسعة التي تمت إضافتها إلى UNIX بعد تطبيق التعبير النمطي الأصلي من قبل “كين تومسون”. حيث يبحث تطبيق “كين تومسون” عن أي قائمة من العبارات النصية الثابتة باستخدام خوارزمية Aho-Corasick. يتم تضمين هذه المتغيرات في معظم تطبيقات Grep الحديثة كمفاتيح تبديل لسطر الأوامر (وموحدة مثل خيارات E- و F- في POSIX.2). قد يتصرف Grep أيضًا في مثل هذه التطبيقات المدمجة بشكل مختلف اعتمادًا على الاسم الذي تم استدعاءه به، مما يسمح لـ fGrep و eGrep و Grep بأن تكون روابط للبرنامج نفسه.
هناك طريقتان لتوفير المدخلات إلى Grep ولكل منها استخداماته الخاصة. أولاً: يمكن استخدام Grep للبحث في ملف أو ملفات معينة في النظام (بما في ذلك البحث المتكرر من خلال المجلدات الفرعية).
يقبل Grep أيضًا المدخلات من أمر أو سلسلة أوامر أخرى.
- التعبيرات النمطية
- الاستخدام الأساسي
- استخدام التعبيرات النمطية
- قائمة الأحرف في التعبيرات النمطية
- رموز الأسطر والحروف
- استخدام أوامر shell في تعبيرات Grep
التعبيرات النمطية
التعبير النمطي (regular expression) غالبًا ما يتم اختصاره إلى “regex” أو “regexp” وهو كما شرحناه في الأعلى. تعمل Regexes بشكل متقدم في معالجة محتوى النص بشكل مفيد خاصةً عند دمجها مع أوامر أخرى. يتم عادةً تضمين التعبيرات النمطية في أمر Grep بالتنسيق التالي:
1
grep [خيارات] [regexp] [اسم الملف]
يستخدم GNU Grep إصدار GNU من التعبيرات النمطية وهو مشابه جدًا (ولكن ليس مطابقًا) للتعبيرات المعتادة POSIX. تتشابه في الواقع معظم أنواع التعبيرات المعتادة تمامًا لكن لها اختلافات في حالات الهروب (Escape) أو أحرف التعريف أو العوامل الخاصة.
يحتوي GNU Grep على مجموعتين من ميزات التعبير النمطي: أساسي وموسَّع (Basic and Extended).
في التعبيرات النمطية الأساسية: تفقد الأحرف الوصفية ؟
و +
و {
و |
و (
و )
معناها الخاص والذي يرد وصف لاستخداماته لاحقًا في هذه المقالة. وكما هو مذكور أدناه، للتبديل إلى استخدام التعبيرات النمطية الموسعة تحتاج إلى إضافة الخيار E- إلى الأمر grep.
من المعتاد إحاطة التعبير النمطي بعلامات تنصيص مفردة (أي ' '
) لمنع موجه الأوامر shell (مثل Bash أو غيرها) من محاولة تفسير التعبير وتوسيعه قبل بدء عملية grep. على سبيل المثال إذا لم يتم تضمين الرمز `
بعلامتي تنصيص مفردة ' '
فسوف يتم تنفيذ النص بين علامتي `
كعملية فرعية لـ Bash - وإذا حدث أن ذلك أمر صالح فالنص المُرجع سيأخذ مكان التعبير النمطي في تعليمة سطر الأوامر المعطاة إلى Grep! وليس هذا مانريد.
مرة أخرى، نظرًا لسلوك shell يمكنك أيضًا تضمين regex في علامات تنصيص مزدوجة " "
وفي هذه الحالة يمكنك استخدام متغيرات البيئة في regex، وستقوم shell باستبدالها قبل تنفيذ Grep. قد يكون هذا مفيدًا جدًا اعتمادًا على ما تحاول القيام به، أو قد يكون مصدر إزعاج. تذكر الفرق في السلوك.
الاستخدام الأساسي
دعنا ننتقل الآن إلى بعض الأمثلة العملية لاستخدام Grep. ولفهم النتائج بشكل أفضل قمت بإنشاء ملف نصي بسيط سنقوم بتشغيل عمليات البحث الخاصة به في Grep. يحتوي الملف على الأسطر التالية:
1
2
3
4
5
6
7
8
Hi
this
is test file
to carry out few regular expressions
practical with grep
123 456
Abcd
ABCD
بحث غير حساس لحالة الأحرف (grep -i):
1
2
3
$ grep -i 'abcd' testfile
Abcd
ABCD
كما ترى فالخيار i- يؤدي للبحث عن “abcd” لإرجاع المطابقات التي لها حالات مختلفة للأحرف (أي سواء كانت الأحرف كبيرة أو صغيرة).
البحث عن كلمة كاملة (grep -w):
1
2
$ grep -w 'test' testfile
is test file
هذا النوع من البحث يعرض فقط الأسطر التي تكون فيها العبارة المطلوبة كلمة كاملة وليست جزءًا من كلمة (مثلا حرفين من كلمة).
البحث بشكل متكرر من خلال المجلدات الفرعية (grep -r <pattern> path):
1
2
$ grep -r '456' /root/
/root/testfile:Year is 2010
البحث العكسي (grep -v):
1
2
3
4
5
6
7
8
$ grep -v 'practical' testfile
Hi
this
is test file
to carry out few regular expressions
123 456
Abcd
ABCD
الأمر أعلاه يعطي جميع الأسطر في الملف، باستثناء السطر الذي يحتوي على كلمة “practical”.
من الاستخدامات المثيرة للاهتمام أيضا هي علامة L- (يمكنك أيضًا استخدام –files-without-match ) ، والذي يعطي أسماء الملفات التي لا تحتوي على تطابقات لنمط البحث الخاص بك. لا تتم طباعة العبارات التي تتطابق مع نمط البحث بل يتم طباعة أسماء ملفاتها فقط.
1
2
3
4
5
6
7
[manish@clone ~]$ grep -r -L "Network" /var/log/*
/var/log/anaconda.log
/var/log/anaconda.syslog
/var/log/audit/audit.log
/var/log/boot.log
/var/log/boot.log.1
...
الخيار المعاكس لـ L- هو l- أو files-with-matches– والذي يطبع (فقط) أسماء الملفات التي تحتوي على تطابق لنمط البحث الخاص بك.
طباعة أسطر إضافية (زائدة) بعد المطابقة (grep -A NUM):
1
2
3
[manish@clone ~]$ grep -A1 '123' testfile
123 456
Abcd
يطبع Grep السطر المطابق لكل سطر يطابق البحث، وكذلك السطر الذي يليه. يؤدي تغيير الرقم المعطى إلى A- إلى تغيير عدد الأسطر الإضافية الموجودة في الخرج.
لطباعة أسطر سابقة إضافية (قبل السطر الذي يحوي التطابق) (grep -B NUM):
1
2
3
4
[manish@clone ~]$ grep -B2 'Abcd' testfile
practical with grep
123 456
Abcd
طباعة أسطر إضافية (سابقة ولاحقة) قبل وبعد المطابقة (grep -C NUM):
1
2
3
4
5
6
[manish@clone ~]$ grep -C2 'carry' testfile
this
is test file
to carry out few regular expressions
practical with grep
123 456
كما ترى ، فقد طبع هذا الأمر سطرين قبل وبعد سطر المطابقة الموجود في الملف. إذا كان هناك تطابقات متعددة فسيقوم Grep بإدراج سطر يحتوي على الرمزين --
بين كل مجموعة من الأسطر (كل تطابق وأسطره الخاصة به).
طباعة اسم الملف لكل مطابقة (grep -H <pattern> filename):
1
2
3
[manish@clone ~]$ grep -H 'a' testfile
testfile:to carry out few regular expressions
testfile:practical with grep
لنجري الآن البحث بشكل مختلف قليلاً:
1
2
3
[manish@clone ~]$ cat testfile | grep -H 'a'
(standard input):to carry out few regular expressions
(standard input):practical with grep
عندما يتم تمرير الدفق (ملف أو مجموعة ملفات) الذي يُطلب من Grep بحثه إلى مدخلاته القياسية عبر توجيه من أمر سابق في السلسلة، يعرض grep -H (الإدخال القياسي) كاسم ملف.
التنفيذ في الوضع “الصامت” (grep -q): عند التنفيذ باستخدام هذا الخيار فلا يطبع Grep أي شيء إلى الخرج القياسي، بل يحدد قيمة الإرجاع لتعكس ما إذا كان قد تم العثور على تطابق أم لا. يستخدم هذا الخيار بشكل أساسي في البرامج النصية التي تحتاج إلى التحقق مما إذا كان الملف المحدد يحتوي على تطابق معين أم لا. تشير حالة الإرجاع 0 (صفر) إلى أنه تم العثور على تطابق ؛ 1 يشير إلى أنه لم يتم العثور على تطابق.
1
2
3
4
5
6
[manish@clone ~]$ grep -q '2010' testfile
[manish@clone ~]$ echo $?
1
[manish@clone ~]$ grep -q '456' testfile
[manish@clone ~]$ echo $?
0
استخدام التعبيرات النمطية
1
2
[manish@clone ~]$ grep 'c.r' testfile
to carry out few regular expressions
في البحث أعلاه، يستخدم رمز النقطة .
لمطابقة أي حرف مفرد، وهذا هو السبب في أنه يطابق “car” في “carry”. يمتلك Grep محركًا قويًا لتطابق التعبيرات النمطية، والذي لا يمكننا تغطيته بعمق هنا، لكننا سنتحدث عن بعض النقاط الهامة:
-
معظم الأحرف بما في ذلك جميع الحروف والأرقام هي في الواقع تعبيرات نمطية تتطابق مع نفسها.
-
يمكن تحويل أي علامة خاصة لها دلالة في grep (مثل النقطة
.
في المثال أعلاه) إلى حرف عادي عن طريق وضع علامة\
قبلها. هذا يجعل Grep يعاملها كحرف عادي.1 2
[manish@clone ~]$ grep 'c\.r' testfile [manish@clone ~]$
كما ترى، السابقة \
قبل الرمز .
أزالت أهميته كرمز خاص.
يمكن أن يتبع التعبير العادي أحد عوامل التكرار التالية:
- تطابق النقطة
.
أي حرف مفرد. - الرمز
؟
يعني أن العنصر السابق اختياري ، وإذا تم العثور عليه ، فسيتم مطابقته على الأكثر مرة واحدة. - الرمز
*
يعني أن العنصر السابق سيتم مطابقته صفر مرة أو أكثر. - الرمز
+
يعني أن العنصر السابق سيتم مطابقته مرة واحدة أو أكثر. - الرمز
{n}
(بما في ذلك الأقواس) يعني أن العنصر السابق يتم مطابقته تمامًا n مرة ، بينما{,n}
يعني أن العنصر يتم مطابقته n مرة أو أكثر. وكذلك{n، m}
تعني أن العنصر السابق يتم مطابقته على الأقل n مرة ، ولكن ليس أكثر من m مرة.{m,}
يعني أن العنصر السابق مُطابَق على الأكثر m مرة.
ومع ذلك ، فإن عوامل التكرار هي جزء من صيغة التعابير النمطية الموسعة الخاصة بـ GNU Grep ، لذلك لاستخدامها بفعالية ، تذكر إضافة خيار E- إلى الأمر .
قائمة الأحرف في التعبيرات النمطية
تعد أداة “قائمة الأحرف” واحدة من أكثر ميزات التعبيرات النمطية استخدامًا ومرونة. وهي عبارة عن قائمة ضمن الأقواس [ ]
تحوي الأحرف التي نريد مطابقتها. هناك طريقتان أساسيتان لاستخدام قوائم الأحرف: لتحديد قائمة من الأحرف (على سبيل المثال [aeiou] هي قائمة بالأحرف الصوتية) ، أو نطاق (مثل [m-t] ، يمتد إلى [mnopqrst]). النطاقات تعطي مرونة بحيث توفر كتابة سلسلة كاملة من الحروف.
ستتطابق قائمة مؤلفة من حرف واحد مع حرف واحد فقط ؛ ولمطابقة الحرف أكثر من مرة عليك باستخدام عوامل التكرار المشروحة أعلاه، على سبيل المثال للعثور على سلسلة مكونة من 11 حرفًا تحتوي على أحرف أبجدية صغيرة فقط ، سيكون التعبير هو:
1
[a-z] {11}
بعبارة أخرى: العثور على أي حرف من a إلى z إحدى عشرة مرة.
كما ذكرنا سابقًا ، لاستخدام عوامل التكرار ، نحتاج إلى إضافة الخيار E-. لنجرب هذا في ملف الاختبار “testfile”:
1
2
[manish@clone ~]$ Grep -E '[a-z]{11}' testfile
to carry out few regular expressions
تعد هنا الكلمة “expressions” هي الوحيدة المكونة من 11 حرفًا في الملف ؛ لذلك هذا هو السطر الوحيد الناتج عن الأمر.
هناك عدد لا بأس به من قوائم الأحرف التي يتم استخدامها بشكل واسع في التعبيرات النمطية، ويتم إعطاؤها كقوائم معرفة. على سبيل المثال ، تملك القائمة [a-z] من الحروف الأبجدية الصغيرة التي استخدمناها أعلاه، القائمة المعرفة [:lower:]. وهكذا فإن [:upper:] عبارة عن أحرف كبيرة من A إلى Z ، و [:alpha:] هي كل الأحرف الأبجدية ، أي تكافئ كلا القائمتين [:lower:] و [:upper:] مجتمعتين. والقائمة المعرَّفة [:digit:] هي الأرقام من 0 إلى 9 ، و [:alnum:] هي أحرف أبجدية وأرقام أي مزيج من [:alpha:] و [:digit:]. وهناك قوائم معرفة أكثر يمكن إيجادها في دليل Grep الرسمي.
عندما يتم استخدام الرمز ^
في بداية قائمة أحرف، فهذا يمثل نفي للأحرف، بمعنى آخر: “لا شيء من هذه الأحرف”.
رموز الأسطر والحروف
يحدد الرمز ^
أن التعبير الذي يليه يجب أن يكون في بداية السطر:
1
2
[manish@clone ~]$ grep '^th' testfile
this
والرمز $
يعني أن التعبير الذي يسبقه يجب أن يكون في نهاية السطر
1
2
[manish@clone ~]$ grep 'i$' testfile
Hi
العامل >\
يحدد بداية الكلمة.
1
2
[manish@clone ~]$ grep '\<fe' testfile
to carry out few regular expressions
وبالمثل فإن العامل <\
يحدد نهاية الكلمة
1
2
[manish@clone ~]$ grep 'le\>' testfile
is test file
يمكن استخدام العامل b\
(حدود الكلمة) بدلًا من <\
و >\
لتحديد بداية أو/و نهاية الكلمة
1
2
[manish@clone ~]$ grep -e '\breg' testfile
to carry out few regular expressions
وأخيرا ، فإن العامل |
(عامل التناوب) أو باختصار يعني “أو”، وهو جزء من ميزات regex الموسعة. يطابق النمط الذي يحتوي على هذا العامل الأجزاء (التعبيرات) الموجودة على جانبيه (على يمينه أو يساره) بشكل منفصل؛ إذا تم العثور على أي واحد (أحدهما، هذا “أو” ذاك)، فإن السطر الذي يحتوي عليه هو تطابق. يمكن أن تكون الأجزاء نفسها عبارة عن تعبيرات منتظمة معقدة ، وهذا يعني أنه يمكنك التحقق من كل سطر في ملف بحثًا عن أنماط بحث متعددة في مسار واحد.
1
2
3
[manish@clone ~]$ grep -E 'hi|bc' testfile
this
Abcd
كان ذلك بسيطًا جدًا ؛ لذلك دعنا نجرب تعبيرا أكثر تعقيدا. هل يمكنك أن تعرف سبب ظهور الأسطر الناتجة الخاصة بـ regex كما هو موضح أدناه؟
1
2
3
4
5
[manish@clone ~]$ grep -E '^[t-z]+|[^a-z]+$' testfile
this
to carry out few regular expressions
123 456
ABCD
استخدام أوامر shell في تعبيرات Grep
كما ذكرنا سابقًا ، إذا لم تقم بوضع علامة اقتباس مفردة على التعبير الذي يتم تمريره إلى Grep ، فيمكن تنفيذ أمر shell أو يعني أمرا في موجه الأوامر (التيرمينال) بحيث يتم إعطاء عنصر متغيّر إلى الـ Grep. يمكن القيام بذلك عن قصد ، عندما تدعو الحاجة. دعنا ننظر إلى بعض الأمثلة:
1
2
3
[root@clone ~]# grep "$HOME" /etc/passwd
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
نستخدم هنا علامات الاقتباس المزدوجة عن قصد لجعل Bash shell أو موجه الأوامر يستبدل المتغير HOME$ بالقيمة الفعلية للمتغير (في هذه الحالة: root/). وبالتالي ، يبحث Grep في الملف etc/passwd/ عن النص root/ ، مما يؤدي إلى السطرين المتطابقين في البحث.
1
2
3
[root@clone ~]# grep `whoami` /etc/passwd
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
الأمر هنا ضمن العلامتين ` `
يتم تنفيذه من خلال موجه الأوامر، وبالتالي يتم استبدال الأمر whoami بناتجه والذي هو اسم المستخدم الحالي (root).
إلى هنا آمل أن يكون الشرح قد أفادك ووضعك في بداية الطريق لاستخدام هذه الأداة الفعالة.
هذا المقال مترجم وبتصرّف. المصدر