sed أساسيات استخدام المحرر التدفقي Sed لتعديل النصوص في نظام لينكس


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

تمهيد

المُحرِّر التدفقي sed‏ (Stream EDitor) هو محرِّر نصيّ يُجري عمليات التعديل على المعلومات الآتية من مجرى الإدخال القياسي (Standard Input) أو من ملف. يجري المُحرِّر sed عملياته على النصوص سطرًا بسطر بطريقةٍ غير تفاعلية،. هذا يعني إمكانية تحديد التعديلات التي تريد إجراءها أثناء كتابتك للأمر ومن ثم سيُنفِّذها sed تلقائيًا، دون أن يستشيرك في كلّ مرة؛ ربما تجد هذا الموضوع مُربِكًا وغريبًا، لكن اعلم أنَّ هذه الطريقة غير التفاعلية فعّالةٌ جدًا وسريعةٌ لتعديل النصوص.

main.png

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

أساسيات استخدام sed

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

عليك أن تتنبّه إلى طباعة الأمر sed لجميع مخرجاته إلى مجرى الإخراج القياسي (Standard output) مبدئيا؛ وهذا يعني طباعة النتائج إلى الشاشة بدلًا من حفظها في ملفٍ ما، إلا إذا أجريت عملية إعادة توجيه (Output redirection).
الصيغة العامّة لاستخدام هذا المُحرِّر هي:

sed [options] commands [file-to-edit]

لننسخ بعض الملفات النصية إلى مجلد المنزل الخاص بنا للتدرّب على عمليات التعديل:

cd
cp /usr/share/common-licenses/BSD .
cp /usr/share/common-licenses/GPL-3 .

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

sed '' BSD

الناتج:

Copyright (c) The Regents of the University of California.
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
   notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
   notice, this list of conditions and the following disclaimer in the
   documentation and/or other materials provided with the distribution.
...
…

يعمل الأمر السابق كما توقعنا لعدم وجود أيّة تعليمات تعديل ضمن علامتَيْ الاقتباس ''، مما أدى إلى طباعة كل سطر كما هو إلى مجرى الإخراج القياسي (أي إلى الشاشة).
سنشرح كيف يستطيع الأمر sed الحصول على النصوص عبر مجرى الإدخال القياسي بتمرير ناتج الأمر cat عبر أنبوب (pipe، باستعمال الرمز |) إلى الأمر sed، وسنلاحظ ظهور الناتج السابق نفسه:

cat BSD | sed ''

المخرجات:

Copyright (c) The Regents of the University of California.
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
   notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
   notice, this list of conditions and the following disclaimer in the
   documentation and/or other materials provided with the distribution.
. . .
. . .

كما لاحظنا، يمكننا إجراء العمليات بسهولة على الملفات أو على مجرى من النص (آتٍ من أحد الأوامر).

طباعة أسطر معيّنة

رأينا في المثال السابق أنَّ تمرير النص إلى الأمر sed دون استخدام أيّة تعليمات تعديل سيؤدي إلى طباعة النتائج مباشرةً إلى مجرى الإخراج القياسي.
سننظر الآن إلى تعليمة طباعة الأسطر الموجودة في sed، والتي نستطيع استخدامها عبر وضع المحرف p ضمن علامتَي الاقتباس.

sed 'p' BSD

الناتج:

Copyright (c) The Regents of the University of California.
Copyright (c) The Regents of the University of California.
All rights reserved.
All rights reserved.


Redistribution and use in source and binary forms, with or without
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
modification, are permitted provided that the following conditions
are met:
are met:
. . .
. . .

نلاحظ أنَّ sed قد طبع كل سطر مرتين، وهذا بسبب طباعته لكل سطر تلقائيًا، ولأننا طلبنا ذلك مرةً أخرى عبر استعمال تعليمة الطباعة p.

إذا أمعنتَ النظر في الناتج السابق، فستلاحظ أنَّ sed قد طبع أوّل سطر مرتين، متبوعًا بالسطر الثاني مرتين …إلخ. وسترى أنَّ المُحرِّر sed يُجرى عملياته على الأسطر فرادى. حيث يقرأ سطرًا من النص، ثم يجري عمليات التعديل عليه، ثم يخرج النص الناتج قبل تكرار نفس العملية على السطر الذي يليه.
يمكننا إصلاح الناتج السابق عبر تمرير الخيار ‎-n إلى sed، والذي يمنعه من طباعة الأسطر تلقائيًا:

sed -n 'p' BSD

الناتج:

Copyright (c) The Regents of the University of California.
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
   notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
   notice, this list of conditions and the following disclaimer in the
   documentation and/or other materials provided with the distribution.
. . .
. . .

نلاحظ الآن أنَّ كل سطر طُبِعَ مرةً واحدةً فقط.

المجالات

لا أظن أنَّ الأمثلة السابقة تُحسَب على أنها «تعديلات» (إلا إذا كنت تريد طباعة كل سطر مرتين…)؛ لنعدِّل الآن الناتج بجعل sed يطبع أوّل سطر فقط:

sed -n '1p' BSD

الناتج:

Copyright (c) The Regents of the University of California.

بوضع الرقم 1 قبل تعليمة الطباعة، فسنخبر sed ما هو السطر الذي نريد إجراء عمليات التعديل عليه. يمكننا أيضًا طباعة أوّل خمسة أسطر (لا تنسَ استخدام الخيار ‎-n):

sed -n '1,5p' BSD

الناتج:

Copyright (c) The Regents of the University of California.
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions

أعطينا مجالًا من الأسطر للأمر sed السابق. وإذا أعطيت sed مجالًا، فهذا يعني رغبتك بإجراء عمليات التعديل على تلك الأسطر فقط. وأخبرنا –في المثال السابق– الأمر sed أن يطبع الأسطر 1 إلى 5. يمكننا تحديد المجال السابق بطريقةٍ أخرى، وذلك بتحديد بداية مجال الأسطر ومن ثم استخدام معامل إزاحة لكي نخبر sed كم سطرًا عليه أن يتنقل للوصول إلى نهاية المجال:

sed -n '1,+4p' BSD

سيُنتِج الأمر السابق الناتج نفسه، وذلك لأننا أخبرنا sed أن يبدأ المجال من السطر الأول وينتهي بعده بأربعة أسطر.
إذا أردنا أن نتخطى سطرًا بين كل سطرين، فيمكننا تحديد «الخطوة» بعد استخدام المحرف ~. سنطبع في المثال الآتي سطرًا كل سطرين وذلك بدءًا من السطر 1:

sed -n '1~2p' BSD

الناتج:

Copyright (c) The Regents of the University of California.

modification, are permitted provided that the following conditions
1. Redistributions of source code must retain the above copyright
2. Redistributions in binary form must reproduce the above copyright
   documentation and/or other materials provided with the distribution.
   may be used to endorse or promote products derived from this software
. . .
. . .

حذف الأسطر

يمكننا بسهولة إجراء عمليات حذف للأسطُر بدلًا من طباعتها، وذلك بتبديل الأمر p إلى الأمر d.
لم نعد نحتاج الخيار ‎-n لأنَّ الأمر sed – عند استخدام تعليمة الحذف معه – سيطبع كل شيء لم يُحذَف، مما يساعدنا في معرفة ماذا عُدِّل.
يمكننا تعديل آخر أمر من القسم السابق ليحذف سطرًا كل سطرين بدءًا من أوّل سطر. يجب أن يظهر في ناتج تنفيذ هذا الأمر كلُّ سطرٍ لم يظهر في ناتج الأمر الذي طبّقناه في القسم السابق:

sed '1~2d' BSD

المخرجات:

All rights reserved.
Redistribution and use in source and binary forms, with or without
are met:
   notice, this list of conditions and the following disclaimer.
   notice, this list of conditions and the following disclaimer in the
3. Neither the name of the University nor the names of its contributors
   without specific prior written permission.
. . .
. . .

من المهم أن تلاحظ أنَّ الملف الأصلي لم يتغيّر قط، فما يزال على حاله، لكن التعديلات التي حدثت قد ظهرت على شاشتنا.
إذا أردنا حفظ تعديلاتنا، فيمكننا إعادة توجيه مجرى الإخراج القياسي إلى ملفٍ كما في الأمر الآتي:

sed '1~2d' BSD > everyother.txt

إذا اطلعتَ على محتويات الملف مستعملًا الأمر cat، فسترى الناتج السابق نفسه. أذكِّرُكَ أنَّ الأمر sed لا يُعدِّل الملف المصدري مبدئيًّا منعًا لحدوث أخطاء.
يمكننا تغيير هذا السلوك الافتراضي باستعمال الخيار ‎-i، الذي يؤدي إلى إجراء التعديلات على الملف الأصلي.
لنجِّرب هذا الخيار على الملف everyother.txt الذي أنشأناه منذ قليل. لنحاول حذف المزيد من الأسطر من هذا الملف:

sed -i '1~2d' everyother.txt

إذا استعملتَ الأمر cat مرةً أخرى، فسترى أنَّ الملف قد عُدِّل.
وكما ذكرنا سابقًا، الخيار ‎-i خطيرٌ ويجب توخي الحذر عند استعماله؛ ولحسن الحظ، يعطينا sed القدرة على إنشاء نسخةٍ احتياطيةٍ مباشرةً قبل التعديل؛ وذلك بوضع لاحقة الملف الاحتياطي مباشرةً بعد الخيار ‎-i كما يلي:

sed -i.bak '1~2d' everyother.txt

الأمر السابق سيؤدي إلى إنشاء ملفٍ احتياطيٍ باللاحقة ‎.bak، ثم تعديل الملف الأصلي مباشرةً.

استبدال النصوص

أحد أشهر استخدامات المُحرِّر sed هو استبدال النصوص. يملك المُحرِّر sed القدرة على البحث عن أنماطٍ نصيةٍ عبر التعابير النمطية (Regular expressions) ومن ثم استبدال النص المُطابِق.
يمكنك مراجعة هذه المقالة لمزيدٍ من المعلومات حول التعابير النمطية.
يمكنك استبدال كلمة بأخرى عبر الصيغة البسيطة الآتية:

's/old_word/new_word/'

المحرف s يُمثِّل عملية الاستبدال (تذكّر أنَّ كلمة «استبدال» بالإنكليزية هي «Substitute»)، وتُستعمَل الخطوط المائلة / لفصل مختلف الحقول؛ لكن يمكنك استخدام محارف أخرى للفصل بين الحقول إذا ارتأيتَ فائدةً من ذلك.
على سبيل المثال، إذا كنتَ تحاول تغيير اسم الصفحة في رابط URL، فيمكنك استخدام حرف آخر للفصل بين الحقول (مثلا _) لأنَّ عناوين URL تحتوي على خطوط مائلة / ضمنها. سنفعل ذلك في المثال الآتي الذي نستعمل الأمر echo فيه لتمرير رابط URL عبر أنبوب إلى مجرى الإدخال القياسي للأمر sed:

echo "http://www.example.com/index.html" | sed 's_com/index_org/home_'

الناتج:

http://www.example.org/home.html

لا تنسَ وضع آخر فاصل (المحرف _) أو سيشتكي الأمر sed:

echo "http://www.example.com/index.html" | sed 's_com/index_org/home'

ستظهر رسالة الخطأ الآتية:

sed: -e expression #1, char 22: unterminated `s' command

لنُنشِئ ملفًا للتدرّب على استبدال النصوص (تأكد من كتابة النص على7 أسطُر):

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

لنستبدل الآن التعبير forward بالتعبير on:

sed 's/on/forward/' annoying.txt

الناتج:

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

يمكنك أن تلاحظ بعض الإشكاليات في الناتج السابق. أولها هو أننا نستبدل تعابير وليس كلمات، هذا يعني أنَّ التعبير on الموجود ضمن الكلمة song سيصبح forward.

تظهر الإشكالية الثانية في السطر الثاني، حيث لم يُبدّل تعبير on الثاني إلى forward؛ وهذا لأنَّ الأمر s سيُعدِّل أوّل مطابقة في السطر مبدئيًّا، ثم سينتقل إلى السطر الذي يليه؛ ولجعل الأمر sed يُبدِّل كل التعابير الموجودة في السطر بدلًا من أوّل مطابقة، فعلينا تمرير «راية» (flag) اختيارية إلى تعليمة الاستبدال.
سنوفِّر الراية g إلى تعليمة الاستبدال بوضعها بعد آخر محرف فصل، كما في المثال الآتي:

sed 's/on/forward/g' annoying.txt

الناتج:

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

أصبحت تعليمة الاستبدال تُغيّر كل مُطابَقة في السطر.
لكن إذا أردتَ تغيّر ثاني مطابقة للتعبير on في كل سطر، فيمكنك استخدام الرقم 2 بدلًا من الراية g:

sed 's/on/forward/2' annoying.txt

الناتج:

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

إذا أردت أن ترى ما هي الأسطر التي استبدِلَت، فيمكنك استخدام الخيار ‎-n لإخفاء الأسطر غير المُعدَّلة؛ ثم يمكننا بعد ذلك تمرير الخيار p إلى تعليمة الاستبدال لطباعة الأسطر التي أجريت عليها تلك العملية:

sed -n 's/on/forward/2p' annoying.text

الناتج:

yes, it goes on and forward, my friend

وكما لاحظتَ، يمكننا دمج رايات عدة معًا في نهاية التعليمة.
إذا أردنا البحث مع إهمال اختلاف حالة الأحرف، فيمكننا استعمال الراية i كما في الأمر الآتي:

sed 's/SINGING/saying/i' annoying.txt

الناتج:

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

إعادة استخدام التعابير التي تمت مطابقتها

إذا استخدمنا التعابير النمطية لمطابقة النصوص، فلدينا طرائق مختلفة نستطيع استخدامها للإشارة إلى التعبير الذي تمت مطابقته في النص الذي سنضعه بدلًا من النص الأصلي.
على سبيل المثال، إذا أردنا أن نطابق من بداية السطر إلى التعبير at، فيمكننا استخدام الأمر الآتي:

sed 's/^.*at/REPLACED/' annoying.txt

الناتج:

REPLACED never ends
yes, it goes on and on, my friend
some people started singing it
REPLACED it was
and they'll continue singing it forever
just because…

لاحظ أنَّ المحرف البديل * أدى إلى المطابقة من بداية السطر ^ إلى آخر مُطابَقة للتعبير at. ولعدم معرفتك ما هي العبارة التي ستُطابَق في تعبير البحث، فيمكنك استخدام الرمز & في تعبير الاستبدال لتمثيل النص الذي جرت مُطابقته.
هذا المثال يُظهِر كيف نستطيع وضع قوسين حول النص المُطابَق:

sed 's/^.*at/(&)/' 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…

طريقة أخرى أكثر مرونةً للإشارة إلى النص المُطابَق هي استخدام أقواس هلاليّة () لتجميع أقسام من النص المُطابق.
يمكن الإشارة إلى كل مجموعة من النص المُطابَق والمحاط بالأقواس الهلالية عبر استخدام الأرقام. فمثلًا، نُشير إلى أوّل مجموعة تعابير محاطة بقوسين هلاليين بالتعبير ‎\1، والمجموعة الثانية بالتعبير ‎\2 وهكذا.
سنُبدِّل في هذا المثال بين أوّل كلمتين في كل سطر (لا تنسَ «تخليص» [escape] الأقواس الهلالية ضمن التعابير النمطية):

sed 's/\([a-zA-Z0-9][a-zA-Z0-9]*\) \([a-zA-Z0-9][a-zA-Z0-9]*\)/\2 \1/' annoying.txt

الناتج:

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

يمكنك ملاحظة أنَّ الناتج ليس مثاليًا؛ فمثلًا، سنتجاهل أوّل كلمة لأنها تحتوي على محرف ليس مذكورًا ضمن مجموعة المحارف التي نريد مطابقتها. وستُعامَل they'll ككلمتين في السطر الخامس.
لنحسِّن من التعبير النمطي السابق ليصبح أكثر دقةً:

sed 's/\([^ ][^ ]*\) \([^ ][^ ]*\)/\2 \1/' annoying.txt

الناتج:

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

الناتج أفضل بكثير من الناتج السابق، حيث ستُجمَّع علامات الترقيم مع الكلمة التي تتبع لها.
لاحظ كيف كرَّرنا التعبير داخل القوسين (مرةً دون استخدام المحرف *، ومرةً معه). وهذا لأنَّ المحرف * يؤدي إلى مطابقة مجموعة المحارف التي تسبقه عندما تقع 0 مرة أو أكثر.
وهذا يعني أنَّ التعبير سيُطابَق حتى لو لم يُعثَر على النمط ضمن النص؛ وللتأكد من وجود التعبير مرةً واحدةً على الأقل، فعلينا مطابقته أولّا دون استخدام *.

الخلاصة

لقد شرحنا بعض أساسيات استخدام الأمر sed، أتوقع أنَّك عرفتَ الآن سهولة وسرعة تعديل النصوص باستخدام أوامر sed.
سنشرح في الدرس القادم ميزاتٍ متقدّمة للمحرِّر sed.

ترجمة –وبتصرّف– للمقال The Basics of Using the Sed Stream Editor to Manipulate Text in Linux لصاحبه Justin Ellingwood





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


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



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

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

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


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

تسجيل الدخول

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


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