تمهيد
المُحرِّر التدفقي sed هو أداةٌ قويةٌ جدًا لتعديل النصوص، حيث تستطيع باستخدامها معالجة النصوص بجهدٍ بسيط. ناقشنا في الدرس السابق أساسيات استخدام المحرر Sed، وسنكمل مشوارنا في هذا الدرس بشرح بعض المواضيع المتقدمة.
إمكانية تطبيق تغييرات عِدّة معا
هنالك حالاتٌ ترغب فيها بتمرير أوامر 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.
أفضل التعليقات
لا توجد أية تعليقات بعد
انضم إلى النقاش
يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.