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