sed استخدامات متقدمة للمحرِّر Sed في نظام لينكس


عبد اللطيف ايمش

تمهيد

المُحرِّر التدفقي sed هو أداةٌ قويةٌ جدًا لتعديل النصوص، حيث تستطيع باستخدامها معالجة النصوص بجهدٍ بسيط. ناقشنا في الدرس السابق أساسيات استخدام المحرر Sed، وسنكمل مشوارنا في هذا الدرس بشرح بعض المواضيع المتقدمة.

main.png

إمكانية تطبيق تغييرات عِدّة معا

هنالك حالاتٌ ترغب فيها بتمرير أوامر sed عِدّة في الوقت نفسه، وهنالك طرائق عدّة لفعل ذلك.
إذا لم تتوافر عندك الملفات التي عملنا عليها في الدرس السابق، فيمكنك تطبيق هذه الأوامر لإنشائها لكي نعدِّلها في سياق هذا الدرس:

cd
cp /usr/share/common-licenses/BSD .
cp /usr/share/common-licenses/GPL-3 .
echo "this is the song that never ends
yes, it goes on and on, my friend
some people started singing it
not knowing what it was
and they'll continue singing it forever
just because..." > annoying.txt

ولقدرة تعامل الأمر sed مع مجرى الإدخال والإخراج القياسي، فيمكننا استدعاء الأمر sed أكثر من مرة عبر استعمال الأنابيب (pipes، وذلك عبر رمز الخط الشاقولي |). تذكر أنَّ عليك تخليص (escape) المحرف & لأنَّه يحمل معنىً خاصًا في sed:

sed 's/and/\&/' annoying.txt | sed 's/people/horses/'

الناتج:

this is the song that never ends
yes, it goes on & on, my friend
some horses started singing it
not knowing what it was
& they'll continue singing it forever
just because…

لقد نجحت محاولتنا، لكنّ ذلك غير عملي لأننا استدعينا الأمر sed مرات عدّة، وهو أطول، ولن نستفيد من ميزات sed المبنية داخله…
يمكننا إرسال مختلف التعليمات إلى الأمر sed باستخدام الخيار ‎-e قبل كل تعليمة. سنُعيد كتابة الأمر السابق وسنستخدم فيه الخيار ‎-e:

sed -e 's/and/\&/' -e 's/people/horses/' annoying.txt

طريقةٌ أخرى لتنفيذ تعليمات sed عدّة معًا هي استعمال الفاصلة المنقوطة ; لفصل التعليمات عن بعضها. وهذا شبيهٌ بالأمر السابق لكن دون الحاجة إلى استعمال الخيار ‎-e:

sed 's/and/\&/;s/people/horses/' annoying.txt

لاحظ عند استخدامنا للخيار ‎-e أننا احتجنا إلى تضمين التعليمات المختلفة داخل علامتَي اقتباس؛ لكن عندما فصلنا التعليمات عبر الفاصلة المنقوطة فوضعناها جميعًا ضمن سلسلة نصية وحيدة محاطة بعلامتَي اقتباس فقط.
وعلى الرغم من أنَّ الطريقتين السابقتين المستعملتين لتنفيذ تعليمات عدّة معًا مفيدتان، لكن هنالك حالات نضطر فيها إلى تمرير ناتج أحد أوامر sed إلى الآخر عبر أنبوب.
خذ مثلًا المعامل =، الذي يُضيف رقم السطر في سطر جديد قبله. أمعن النظر في ناتج الأمر الآتي:

sed '=' annoying.txt

الناتج:

1
this is the song that never ends
2
yes, it goes on and on, my friend
3
some people started singing it
4
not knowing what it was
5
and they'll continue singing it forever
6
just because…

إذا أردنا تغيير تنسيق الأرقام عبر تعديل النص، فسنجد أنَّ ذلك لا يعمل كما نتوقع.
لشرح هذه الفترة، سنتعلم قليلًا عن التعليمة G التي تُضيف سطرا فارغا بين كل سطرين مبدئيًّا (استخدام هذه التعليمة أكثر تعقيدًا مما سبق، لكننا سنتعلمها لاحقًا):

sed 'G' annoying.txt

الناتج:

this is the song that never ends

yes, it goes on and on, my friend

some people started singing it

not knowing what it was

and they'll continue singing it forever

just because…

إذا دمجنا بين هذين الأمرين، فسنتوقع إضافة سطر فارغ بين كل سطر عادي وسطر يحتوي رقمًا، لكننا سنحصل على ناتجٍ مختلف:

sed '=;G' annoying.txt

الناتج:

1
this is the song that never ends

2
yes, it goes on and on, my friend

3
some people started singing it

4
not knowing what it was

. . .
. . .

ما حدث هو أنَّ المعامل = عدّل مجرى الإخراج مباشرة، وهذا يعني أننا لا نستطيع التعديل على الناتج؛ لكن يمكننا الالتفاف على هذه الإشكالية عبر استدعاء الأمر sed مرتين، مُمرِّرين ناتج أوّل أمر إلى ثاني أمر عبر أنبوب:

sed '=' annoying.txt | sed 'G'

الناتج:

1

this is the song that never ends

2

yes, it goes on and on, my friend

3

some people started singing it
. . .
. . .

سنحصل الآن على الناتج الذي كنّا نتوقعه. أبقِ في ذهنك أنَّ بعض التعليمات تسلك هذا السلوك نفسه، وأتوقع أنَّك ستلاحظ ذلك مباشرةً عندما يختلف الناتج عمّا تتوقعه.

طرائق متقدمة لتحديد المجالات

إحدى ميزات استخدام المجالات (أو العناوين) في sed هي إمكانية استخدام التعابير النمطية معيارًا لتحديد الأسطر التي ستُطبَّق عليها التعليمات، وهذا يعني أننا لسنا محدودين بإمكانية إجراء التعديلات على الأسطر ذات القيمة المعلومة مسبقًا، كما تعلمنا في الدرس السابق:

sed '1,3s/.*/Hello/' annoying.txt

الناتج:

Hello
Hello
Hello
not knowing what it was
and they'll continue singing it forever
just because…

يمكننا –بدلًا مما سبق– استعمال التعابير النمطية لمطابقة الأسطر التي تحتوي أنماطًا معيّنةً، ويمكننا فعل ذلك بوضع تعبير المُطابَقة بين خطين مائلين / قبل البدء بتعريف تعليمات التعديل، كما في المثال الآتي:

sed '/singing/s/it/& loudly/' annoying.txt

الناتج:

this is the song that never ends
yes, it goes on and on, my friend
some people started singing it loudly
not knowing what it was
and they'll continue singing it loudly forever
just because…

وضعنا في المثال السابق الكلمة «loudly» بعد أوّل كلمة «it» في كل سطر يحتوي على السلسلة النصية «singing»، لاحظ أنَّ السطرين الثاني والرابع لم يُعدَّلا لعدم مطابقتهما للتعبير.

قد تمسي التعابير التي تستعمل لتحديد مجالات الأسطر التي ستُنفَّذ عليها التعليمات معقدةً جدًا، لكن ذلك يوفِّر قدرًا كبيرًا من المرونة عند تنفيذ التعليمات.
المثال الآتي ليس معقدًا أبدًا، لكنه يوضِّح كيف يمكن استخدام التعابير النمطية لتحديد مجالات لتُستعمَل مع تعليماتٍ أخرى. هذا التعبير يُطابِق أيّة أسطر فارغة (التعبير النمطي يُطابِق بداية السطر متبوعةً مباشرةً بنهاية السطر) ومن ثم تمرير هذه المجال من الأسطر إلى تعليمة الحذف:

sed ‘/^$/d’ GPL-3

الناتج:

                    GNU GENERAL PUBLIC LICENSE
                       Version 3, 29 June 2007
 Copyright (C) 2007 Free Software Foundation, Inc. 
 Everyone is permitted to copy and distribute verbatim copies
 of this license document, but changing it is not allowed.
                            Preamble
  The GNU General Public License is a free, copyleft license for
. . .
. . .

أبقِ في ذهنك أنَّنا نستطيع استعمال التعابير النمطية لتحديد بداية المجال ونهايته؛ فمثلًا، يمكننا حذف جميع الأسطر التي تأتي بعد سطرٍ يحتوي الكلمة «START» حتى يأتي سطرٌ فيه الكلمة «END» بتنفيذ الأمر:

sed '/^START$/,/^END$/d' inputfile

لكن عليك أن تنتبه أنَّ الأمر السابق سيحذف كل شيء بدءًا من أوّل START انتهاءً بأول END، ثم سيُكرِّر عملية الحذف إذا ظهرت الكلمة START مرةً أخرى.

إذا أردتَ عكس المجال (أي تنفيذ التعلميات على الأسطر التي لا تُطابِق النمط)، فيمكنك اتباع النمط بعلامة التعجب !؛ فمثلًا، يمكننا حذف جميع الأسطر غير الفارغة (أعلمُ أنَّ هذا ليس مفيدًا، لكنني أعرضه هنا مثالًا) باستعمال الأمر الآتي:

sed '/^$/!d' GPL-3

الناتج:

 

لاحظ أنَّ بإمكانك استعمال علامة التعجب لعكس مجال التحديد على أي نوع من المجالات كالمجالات الرقمية، وليست حكرًا على التعابير النمطية فقط.

استخدام ذاكرة التخزين (Hold Buffer)

إحدى الميزات التي تزيد من قابلية استخدام sed لإجراء تعديلات على أسطر عدّة معًا تسمى «ذاكرة التخزين» (Hold Buffer)، وهي مكانٌ مؤقتٌ لتخزين النصوص التي يمكن تعديلها من تعليمات عدّة.
وجود هذه الذاكرة يعني أننا نستطيع تخزين بعض الأسطر أثناء عملنا على أسطرٍ أخرى، ويمكننا إجراء العمليات على كلٍّ منها عند الحاجة.

هذه هي التعليمات التي تستخدم مع ذاكرة التخزين:

  • h: نسخ السطر المُطابَق (والذي نعمل عليه حاليًا) إلى ذاكرة التخزين (مما يؤدي إلى حذف المحتوى الذي كان موجودًا في ذاكرة التخزين).
  • H: إضافة السطر المُطابَق إلى ذاكرة التخزين في نهايتها، وسيُوضَع قبله محرف السطر الجديد ‎\n.
  • g: وضع محتويات ذاكرة التخزين مكان السطر المُطابَق (مما يؤدي إلى حذفه).
  • G: إضافة محتويات ذاكرة التخزين إلى السطر المُطابَق مع فصلهما بمحرف السطر الجديد ‎\n.
  • x: التبديل بين السطر المُطابَق وذاكرة التخزين.

لنستكشف هذه الفكرة عبر تفحّص أحد الأمثلة المعقدة قليلًا.
هذا المثال يبيّن كيفية دمج الأسطر المتجاورة مع بعضها بعضًا (في الواقع، يملك sed تعليمةً لفعل ذلك بسهولة وهي التعليمة N التي تدمج كل سطر إلى السطر الذي يسبقه، لكننا سنفعل ذلك يدويًا للتدرّب):

sed -n '1~2h;2~2{H;g;s/\n/ /;p}' annoying.txt

الناتج:

this is the song that never ends yes, it goes on and on, my friend
some people started singing it not knowing what it was
and they'll continue singing it forever just because…

الأمر السابق يبدو مخيفًا! لنقسِّمه إلى أجزاء ليسهل فهمه.

أوّل شيء علينا ملاحظته هو أننا استعملنا الخيار ‎-n لإيقاف طباعة الأسطر تلقائيًا، مما يؤدي إلى عدم طباعة أيّة أسطر إلا التي نطلب من sed إخراجها.
أوّل جزء من التعليمة هو ‎1~2h وأوّل قسم منها هو مجالٌ من الأسطر والذي يعني أنَّ على sed تنفيذ التعليمات على الأسطر ذات الأرقام الفردية بدءًا من السطر الأول (أي تخطي سطر بين كل سطرين)؛ أما h فهي تعليمة نسخ الأسطر المُطابَقة إلى ذاكرة التخزين.
الجزء الثاني من التعليمة أكثر تعقيدًا، حيث يبدأ بمجال يُحدِّد الأسطر ذات الأرقام الزوجية (أي عكس المجال السابق).
تُحتوى بقية التعليمة بين قوسين معكوفين، وهذا يعني أنَّ جميع الأوامر الموجودة بين القوسين ستُطبَّق على المجال المُحدَّد؛ وفي حال لم نستعمل الأقواس فستُطبَّق التعليمة H على المجال فقط، وبقية التعليمات ستُنفَّذ على جميع الأسطر.
التعليمة H ستؤدي إلى نسخ محرف السطر الجديد متبوعًا بالسطر الذي جرت مُطابَقته إلى نهاية ذاكرة التخزين.
ثم نسخنا ذاكرة التخزين (التي تحتوي على سطرٍ ذي رقمٍ فردي متبوع بمحرف السطر الجديد متبوع بسطرٍ ذي رقمٍ زوجي) مكان السطر المُطابَق، وذلك بالتعليمة g.
ثم وضعنا فراغًا بدلًا من محرف السطر الجديد، ومن ثم طبعنا الناتج بالتعليمة p.
وكما ذكرنا آنفًا، استخدام التعليمة N يؤدي إلى تقليل طول الأمر كثيرًا. الأمر التالي يُنتِج الناتج السابق نفسه:

sed -n 'N;s/\n/ /p' annoying.txt

الناتج:

this is the song that never ends yes, it goes on and on, my friend
some people started singing it not knowing what it was
and they'll continue singing it forever just because…

استخدام سكربتات sed

إذا بدأت باستخدام التعليمات المعقدة، فستجد أنَّ من الأسهل كتابتها في محرِّرٍ نصي؛ وهذا مفيدٌ جدًا إذا كانت عندك تعليماتٌ كثيرة وأردتَ تطبيقها جميعها على النص نفسه.

على سبيل المثال، إذا كنتَ تكتب رسائلك الإلكترونية في ملفاتٍ نصيةٍ بسيطة، فقد تُجري عليها بعض عمليات المعالجة لتنسيق النص قبل استخدامه، وفي هذه الحالة ستستفيد من كتابة سكربت sed.
وبدلًا من كتابة أوامر sed كاملة في السكربت، كل ما عليك فعله هو وضع التعليمات في ملف وتمرير هذا الملف كمعطى (argument) إلى sed. أي أنَّ سكربت sed هو قائمة بتعليمات sed فقط (أي الأجزاء التي تضعها عادةً بين علامتي اقتباس مفردتين). مثلًا:

s/this/that/g
s/snow/rain/g
1,5s/pinecone/apricot/g

يمكنك بعدئذٍ استخدام السكربت على النحو الآتي:

sed -f sedScriptName fileToEdit

تسمح لك سكربتات sed بكتابة جميع تعليمات التعديل في ملفٍ واحد، ثم تنفيذه على الملفات النصية التي ترغب بتنسيقها.

الخلاصة

أضفنا المزيد من المعلومات عن المُحرِّر sed إلى جعبتنا في هذه المقالة.
أصدقكَ القول أنَّ تعليمات sed ليست سهلة الفهم من الوهلة الأولى، وعليك تجربتها مرات عدّة لتعتاد استخدامها. ولهذا السبب أنصحك بالتدرّب على إجراء مختلف أنواع التعديلات على النصوص لتحترف استخدام sed.

أرجو أن تكون قد فهمتَ القدرات التي يعطيك إياها المُحرِّر sed عند إجراء تعديلات على النصوص، فكلما ارتقيتَ بمستواك في استخدامه قلَّ الوقت اللازم لإنجاز التعديلات على الملفات النصية.

ترجمة –وبتصرّف– للمقال Intermediate Sed: Manipulating Streams of Text in a Linux Environment لصاحبه Justin Ellingwood.





تفاعل الأعضاء


لا توجد أيّة تعليقات بعد



يجب أن تكون عضوًا لدينا لتتمكّن من التعليق

انشاء حساب جديد

يستغرق التسجيل بضع ثوان فقط


سجّل حسابًا جديدًا

تسجيل الدخول

تملك حسابا مسجّلا بالفعل؟


سجّل دخولك الآن