دليل ميَسَّر لكتابة سكربتات Shell


محمد أحمد العيل

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

أساسيّات كتابة سكربتات Shell

1- تهيئة مجلّد العمل

من الجيّد، قبل البدء في كتابة سكربتات Shell، إعدادُ مجلّد لوضعها فيه. يُنصَح بوضع السكربتات الشّخصيّة في مجلّد يوجد على المسار bin/~. ننشئ هذا المجلّد عبر الأمر التّالي:

mkdir ~/bin

نُضيف مسار المجلّد إلى المتغيّر PATH وذلك بتعديل ملفّ etc/profile/ على النّحو التّالي:

sudo nano /etc/profile

ونُضيف الأسطُر التّالية إلى الملفّ:

PATH=$PATH:$HOME/bin
export PATH

استخدم زرّي CTRL وO لحفظ التّعديلات، وCTRL+X للخروج من محرّر النّصوص nano.

ثمّ نعتمد التّغييرات عبر تنفيذ الأمر:

source /etc/profile

بعض توزيعات لينكس لا تدعم أمر source، في هذه الحالة ينبغي إعادة تشغيل النّظام لاعتماد التّعديلات:

sudo reboot

ملحوظة: للتّأكّد من اعتماد التّغييرات استخدِم الأمر التّالي:

printenv PATH

وتأكّد من وجود مسار مجلّد السكربتات ضمن المسارات العروضة (يُفصَل بين المسارات بنقطتيْن عموديّتيْن هكذا :).

2- إنشاء ملفّ

ينبغي إنشاء ملفّ تنفيذيّ Executable file حتى يُمكن تشغيل السكربت. الأمران التّاليّان يؤدّيان هذه المهمّة؛ الأوّل ينشِئ ملفًّا والثّاني يجعله قابلًا للتّنفيذ:

touch ~/bin/firstscript
chmod +x ~/bin/firstscript

نفتح الملفّ بمحرّر نصوص nano للبدْء في إضافة الأوامر إلى السكربت:

nano ~/bin/firstscript

تجب إضافة السّطر التّالي في بداية الملفّ حتّى يعرف النّظام أنّه سكربت Shell وبالتّالي ينفّذ الأوامر الموجودةَ فيه بالطّريقة الصّحيحة:

#!/bin/sh

أصبح الملفّ الآن جاهِزًا ليستقبل أي أمر من أوامر لينكس، مثلًا:

clear
echo "Hello World!"

نحفظ الملفّ (CTRL+O) ثمّ نخرج من محرّر النّصوص (CTRL+X). تكفي الآن كتابة اسم السكربت ثم الضّغط على Enter لتنفيذه:

firstscript

لا يهمّ من أيّ المسارات نفّذت السكربت، مادام مجلّد العمل موجودًا ضمن متغيّر البيئة PATH.

ينبغي أن تحصُل على النّتيجة التّاليّة:

01_first_script.thumb.png.f065531026ed75

3- مثال لسكربت

يُعدّ التّشغيل الآليّ للأعمال المتكرّرة أحد أكثر المجالات الّتي تُستخدَم فيها سكربتات Shell. على سبيل المثال؛ إذا كنت دائمًا تنقل الكثير من الملفّات إلى مجلّد نسخ احتيّاطي Backup، وليكن backup/~، فإنّ بإمكانك إعداد سكربت ينقل أي ملفّ تحدّده إلى المجلّد المطلوب. بهذه الطّريقة يمكن أن تكتُب:

filebackup file-name1 file-name2 ...

فلنلقِ نظرة على ما نحتاج لمعرفته، قبل البدْء في كتابة السكربتات. أوّل ملحوظة هي أنّ سكربتات Shell لا تستخدم التّرميز الصّلب Hard coding. يعني هذا، في إطار مثالنا، أنّه يمكنك بسهولة تغيير مجلّد النّسخ الاحتيّاطي إذا أردت. كلّ ما عليك فعله هو تعديل أحد الأسطُر الأولى في ملفّ السكربت؛ حيثُ سيظهر المتغيّر الّذي سيخزّن مسار المجلّد مرةً واحدة فقط. لن تحتاج لتعديل ملفّ السكربت لتجربة التّعامل مع المتغيّرات، يمكن ذلك مباشرةً في سطر الأوامر عن طريق كتابة ما يلي:

testvariable=teststring

أعطينا القيمة teststring للمتغيّر testvariable. يطبع أمر echo محتوى المتغيّر (لاحِظ استخدام $ أمام اسم المتغيّر):

echo $testvariable

ستظهر في سطر الأوامر قيمة المتغيّر testvariable أيّ teststring. يمكننا الآن بعد هذا الاختبار البسيط لعمل المتغيّرات البدءُ في كتابة السّكربت؛ الخطوات هي نفسُها الّتي تحّثنا عنها أعلاه: إنشاء الملفّ، جعله قابلًا للتّنفيذ، ثمّ البدْء في تحريره:

touch ~/bin/filebackup
chmod +x ~/bin/filebackup
nano ~/bin/filebackup

ينبغي الانتباه إلى أنّ أي سطر يبدأ بعلامة # تعليق، أي أنّه لن يؤثّر على عمل السكربت إلا إذا أُتبعت # بعلامة تعجّب ! في السّطر الأوّل من برنامجك؛ في هذه الحالة يُطلق عليها اسم shebang والّتي شرحنا سابقًا أنّ نظام التّشغيل يعرف عن طريقها أنّ هذا الملفّ سكربت Shell ويُنفّذ الأوامر الموجودة فيه. يأخذ السكربت الشّكلَ التّالي:

#!/bin/sh
#Backup script
#Description: makes a copy of any given file at the backup folder
#Author: Your Name
#Date: 8/10/2013

#Backup folder; set this variable to any folder you have write permissions on
BACKUPFOLDER=~/backup

#The script will make sure the folder exists
mkdir -p $BACKUPFOLDER

#Now the script will copy the given file to the folder
cp -a $@ $BACKUPFOLDER

نشرح، بعد حفظ الملفّ (CTRL+O) والخروج من محرّر النّصوص (CTRL+X)، عمل السكربت. الأسطُر الأولى كلّها تعليقات؛ عرّفنا بعدها متغيّرًا باسم BACKUPFOLDER نضع فيه مسار المجلّد حيث نُريد نسخ الملفّات. ننفّذ بعدها الأمر mkdir -p $BACKUPFOLDER الّذي يُنشئ مجلّدًا في المسار الموجود في المتغيّر BACKUPFOLDER، إذا كان المجلّد موجودًا مسبقًا لن تظهر أي رسالة خطأ نظرًا لاستخدام خيّار p-. تدلّ علامة @$ في الأمر التّالي، cp، على المعطيات الّتي يمرّرها المستخدِم أثناء تنفيذ السّكربت. لتمرير المعطيات للسكربت فإنّ المستخدِم يكتبها مباشرةً بعد اسم السكربت. يوجد مجلّد الحفظ (وِجهة النّسخ، في هذه الحالة قيمة المتغيّر BACKUPFOLDER) مباشرةً بعد المعطيات الّتي يمرّرها المستخدِم.

لتجربة السكربت نفّذ ما يلي، على اعتبار أنّ file1 وfile ملفّان يوجدان في المجلّد حيثُ تنفّذ السكربت:

filebackup file1 file

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

أوامر أساسيّة في Shell

توجد بعض الأوامر الأساسيّة لعرض المعلومات للمستخدِم، ولأخذها منه أيضًا.

1- أمر echo

يُستخدَم أمر echo لعرض معلومات للمستخدِم، سواءٌ كانت هذه المعلومات نصًّا أو متغيّرات أو خليطًا من الاثنين. يُمكن استخدام الخيّاريْن n- وe- مع أمر echo؛ يمنع خيّار n- طباعة سطر جديد بعد النّصّ المعروض، أما خيّار e- فيُفعّل استخدام مجموعة الرموز التّالية داخل النّصّ:

  • a\: صوت تحذير - Alert sound
  • b\: فراغ للخلف Backspace
  • c\: لا تطبع سطرًا جديدًا
  • e\: مِحرف الخلوص Escape character
  • n\: سطر جديد
  • r\: رجوع إلى السّطر
  • t\: جدولة أفقيّة
  • 0xx\: محرف ASCII
  • \\: خط مائل عكسي Backslash.

على سبيل المثال، يؤدّي الأمران التّاليّان نفس الشّيئ بالضّبط (لاحِظ وجود النّص بين علامتيْ اقتباس):

echo -e “Text\c”
echo -n “Text”

لعرض قيمة متغيّر عن طريق أمر echo أضف اسم المتغيّر مسبوقًا بعلامة $:

string=World!
echo "Hello $string"

يُمكنك خلط نص، أوامر ومتغيّرات في سلسلة محارف String واحدة. يمكنك أيضًا كتابة أمر من سطر واحد يعرض نصًّا من أسطر عديدة؛ كلّ ما عليك فعله هو كتابة n\ في المكان الّذي تُريد بدْءَ سطرٍ جديد منه.

2- تهيئة النّصوص باستخدام أمر echo

يُمكن لأمر echo عرض النّصوص وتهيئتها بألوان وأساليب متنوّعة؛ ولكنّ نتائج هذه التّهيئة قد لا تكون دومًا متشابهة في الطّرفيّات الموجودة. يجب الانتباه إلى أنّ بعض المستخدمين قد لا يرون نتيجة تهيئة النّصوص بنفس الطّريقة الّتي تظهر لديك. لا يُشكّل هذا الأمر، بما أنّ التّغيير ظاهريّ أساسًا، مشكلًا كبيرًا في غالب الأوقات. يُعرَّف كلُّ تخصيص (جعل الخطّ عريضًا Bold، وضع خطّ تحت النّص، أو تلوينه) بمتتاليّة من محارف الخلوص Escape characters، وهي مجموعة من الرّموز تتبع المِحرف `e\’، على النّحو التّالي:

echo -e "This is \e[1mBold"

ينتُج عن الأمر السّابق كتابة الجملة This is Bold مع تمييز كلمة Bold بخط عريض.

يوضّح الجدول التّالي بعض الرّموز شائعة الاستخدام:

خطّ عريضخطّ عاديّخطّ تحت النّصّعكس الألوان
e[1m\e[2m\e[4m\e[7m\


يُمكن استخدام هذه الرّموز معًا للحصول على نصّ عريض ومخطوط تحته، ثمّ إعادة تعيين التّأثيرات باستخدام الرّمز e[0m\:

echo -e "\e[4mThis \e[1mis\e[0m \e[7man example \e[0mstring"

جرّب الأمر وشاهد عمل الرّموز.

يعمل تلوين النّصوص بنفس الطّريقة حيثُ يوجد رمز لكلّ لون. تُدرج رموز الألوان مثل ما تُدرج رموز تهيئة النّص المذكورة في الفقرة السّابقة. يوضّح الجدول التّالي رموز الألوان الأكثر شيوعًا. يوجد رمز للون النّص وآخر لخلفيّته.

أسودe[30m\e[40m\
أحمرe[31m\e[41m\
أخضرe[32m\e[42m\
أصفرe[33m\e[43m\
أزرقe[34m\e[44m\
أرجوانيّe[35m\e[45m\
سماويّe[36m\e[46m\
رمادي فاتحe[37m\e[47m\
اللّون الافتراضيّe[39m\e[49m\

إن أردنا مثلًا نصًّا بلون أحمر فالرّمز هوe[31m\، أمّا إذا أردنا خلفيّة بلون أحمر فالرّمز هو e[41m\.

يُمكنك استخدام ألوان مختلفة لكلّ من النّص والخلفيّة، كما أنّ بإمكانك استخدام رموز تهيئة النّصّ المذكورة في الفقرة السّابقة إلى جانب رموز ألوان النّصّ والخلفيّة.

3- أمر read

يُستدعى أمر read لأخذ بيانات من المستخدِم. يسجّل أمر read كلّ ما يكتبه المستخدِم ابتداءً من استدعاء الأمر إلى أن يضغط على زرّ ENTER، يسجّله في متغيّر. يوجد معطًى واحد للاستخدام مع أمر read وهو اسم المتغيّر الّذي سيُحتفظ فيه بما يكتبه المستخدِم. في ما يلي مثال لسكربت مختصَر يُنشئ مجلّدًا بالاسم الّذي يختاره المستخدِم:

#!/bin/bash
read foldername
mkdir foldername

يُمكن ملاحظة أنّ السكربت السّابق لا يمتلك أيّ واجهة للتّفاعل مع المستخدم. كيف يُمكن للمستخدِم أن يعرف مالّذي عليه كتابته؟

4- مثال على سكربت

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

نعدّ بدايةً الملفّ ونفتحه للتّحرير:

touch ~/bin/filebackup2
chmod +x ~/bin/filebackup2
nano ~/bin/filebackup2

ونُعيد كتابته بحيث تكون لديه واجهة مع المستخدِم:

#!/bin/bash
#Backup script 2.0
#Description: makes a copy of any given file at the backup folder
#Author: Your Name
#Date: 5/27/2015
#Request the backup folder from the user:
echo -e "\e[1m\e[32mFile Backup Utility\n\e[39m\e[0mPlease input your backup folder:"
read BACKUPFOLDER
#The script will make sure the folder exists
mkdir -p $BACKUPFOLDER
#Request files to be backed up:
echo -e "\e[47m\e[30mWhich files do you want backed up?\e[39m\e[49m"
read FILES
cp -a $FILES $BACKUPFOLDER

يُظهر السكربت رسالة للمستخدِم، بطريقة منسَّقة، تدعوه أوّلًا لإدخال اسم المجلّد الّذي ستُحفَظ فيه النّسخ الاحتيّاطيّة ويحتفظ باسم المجلّد في المتغيّر BACKUPFOLDER، ثمّ يُنشئ السكربت المجلّد إن لم يكن موجودًا. الخطوة التّاليّة هيّ إظهار رسالة تطلُب من المستخدم إدراج أسماء الملفّات المُراد نسخُها ويحفظها في متغيّر باسم FILES. الخطوة الأخيرة هي نسخ الملفّات إلى المجلّد عبر الأمر cp.

غطّينا في الفقرات السّابقة الأوامر الأساسيّة الّتي تُمكِّن من كتابة سكربتات تتفاعل مع المستخدِم حتّى يعلم بالضّبط كيف يعمل السكربت ومالمعلومات الّتي يطلُبها. ليست كلّ السكربتات تحتاج إلى واجهة مستخدِم؛ السكربت الأوّل الّذي كتبناه أسرع من الثّاني وأفضل في كثير من الأحيان. لا تُضِف واجهة استخدام إلّا للسكربتات الّتي يحتاج المستخدِم للمساعدة في استخدامها، في هذه الحالة ستحتاج لأمر echo.

التّعليمات الشّرطيّة Conditional statements

تُعدّ التّعليمات الشّرطيّة من الأمور الّتي لا غنى عنها لأيّ لغة برمجة متكاملة. سنتطرّق في هذا الجزء من الدّرس لطريقة وضع شروط وتنفيذ أوامر عند تحقّق - أو عدم تحقّق - هذه الشّروط.

1- أمر if

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

if ls folder
then
echo "Folder exists"
fi

إذا وُجد ملفّ باسم folder فإنّ السّكربت السّابق سيُنفّذ الأمر echo "Folder exists" لأنّ رمز الخروج من أمر ls في هذه الحالة هو 0 (يُشير الرّمز 0 إلى أنّه لا توجد أخطاء في تنفيذ الأمر). أمّا إذا لم يوجد المجلَّد فلن تُعرَض الرّسالة.
يجب أن تتبع كلَّ تعليمة if بthen ,وتُختَم بfi.

إذا أردت التّعامل مع عبارات منطقيّة في تعليمة if فستحتاج لأمر test. توجد في Shell العوامل Operators التّاليّة لمقارنة الأعداد:

  • eq-: يُساوي
  • ne-: لا يُساوي
  • lt-: أصغر من
  • le-: أصغر من أو يُساوي
  • gt-: أكبر من
  • ge-: أكبر من أو يُساوي

توجد طريقتان لكتابة أمر test:

if test 4 -gt 3

أو:

if [ 4 -gt 3]

تؤدّي الكتابتان نفس العمل تمامًا، كما أنّهما تحتاجان أيضًا لthen وfi. مثال:

if [ 20 -lt 10 ]
then
echo "What?"
fi

إذا جرّبت تنفيذ السكربت السّابق فستُلاحِظ ألّا شيءَ يُعرَض على الشّاشة؛ لأنّ الشّرط غير متحقّق، فالعدد 20 ليس أصغر من 10. ماذا لو أردنا عرض رسالة للزّائر في حال عدم تحقّق الشرط، مثل ماهو الحال في المثال السّابق؟

2- أمر else

تُضيف else بديلًا يُنفَّذ عند عدم تحقّق الشّرط في تعليمة if. طريقة الاستخدام:

if [ 20 -lt 10 ]
then
  echo "What?"
else
echo "No, 20 is greater than 10."
fi

في هذا المثال نتحقّق من شرط “20 أصغر من 10”، في حال كان صحيحًا نطبع كلمة “?What”، أمّا إذا لم يكن صحيحًا فنطبع عبارة “No, 20 is greater than 10.” (أي لا، 20 أكبر من 10).

يُمكن، إلى جانب العبارات المنطقيّة، مفارنة سلسلة محارف ضمن تعليمة if/else. تتطلّب مقارنة المحارف صيغةً مختلفة قليلًا عن مقارنة الأعداد، ولكنّها تسخدم أمر test أيضًا. في ما يلي صيغة مقارنة سلسلة محارِف:

  • string = string: تكون العبارة صحيحة عندما تكون السّلسلتان متساويّتيْن
  • string != string: تكون العبارة صحيحة عندما لا تكون السّلسلتان متساويّتيْن.
  • string: سلسلة غير خاويّة أو غير معرَّفة
  • n string-: سلسلة معرَّفة وغير خاويّة
  • z string-: سلسلة معرَّفة وغير خاويّة

توجد أيضًا طُرُق لاختبار خصائص الملفّات:

  • s file-: تكون العبارة صحيحة إذا كان الملفّ file غير فارغ.
  • f file-: عبارة صحيحة إذا كان الملفّ file موجودًا وليس
  • d folder-: العبارة صحيحة إذا كان folder مجلّدًا وليس ملفًّا.
  • w file-: عبارة صحيحة إذا كان يُمكن الكتابة في الملف file
  • r file-: يتحقّق الشّرط عندما يكون الملفّ file للقراءة فقط.
  • x file-: تختبر هل الملفّ قابل للتّنفيذ.

3- تعليمات if متداخلة Nested if’s

يُمكن كتابة تعليمة if كاملة ضمن تعليمة if أخرى، في ما يُعرف بتعليمات if متداخلة. نتعرّف على عمل بتعليمات if المتداخلة في المثال التّالي بالاستعانة بأمر read:

#!/bin/bash
echo "Input which file you want created"
read file
if [ -f $file ]
then
echo "The file already exists"
else
  touch $file
  if [ -w $file ]
  then
    echo "The file was created and is writable"
  else
    echo "The file was created but isn't writable"
  fi
fi

يطلُبُ السكربت من المستخدِم إدخال اسم ملفّ ليُنشئه، ويخزّن اسم الملفّ في المتغيّر file؛ ثمّ يختبر إن كان الملفّ موجودًا f $file-، ويُظهر رسالة بذلك إن كانت نتيجة التّحقّق إيجابيّة وإلّا يُنشئ الملفّ (touch $file). بعد إنشاء الملفّ يختبر هل يُمكن الكتابة عليه (w $file-) وإذا كانت الإجابة نعم يطبع الرّسالة The file was created and is writable وإلّا يطبع رسالة مغايِرة The file was created but isn't writable.

4- مثال على سكربت

نُكمل مع سكربت النّسخ الاحتيّاطي لتحسينه. تتضمّن هذه النّسخة اختبارًا لمعرفة ما إذا كان مجلّد النّسخ موجودًا (d $BACKUPFOLDER-) وما إذا كان لدى المستخدِم امتيّاز Privilege إنشاء مجلّد. نبدأ بإنشاء السّكربت وإعداده:

touch ~/bin/filebackup3
chmod +x ~/bin/filebackup3
nano ~/bin/filebackup3

ثمّ تحريره:

#!/bin/bash
#Backup script 3.0
#Description: makes a copy of any given file at the backup folder
#Author: Your Name
#Date: 9/29/2013
#Request the backup folder from the user:
echo -e "\e[47m\e[1m\e[32mFile Backup Utility\n\e[39m\e[0m\e[47mPlease input your backup folder:"
read BACKUPFOLDER
#The script will make sure the folder exists
if [ -d $BACKUPFOLDER ]
then
  echo "You backup folder exists and will be used."
else
  mkdir $BACKUPFOLDER
  if [ -d $BACKUPFOLDER ]
  then
    echo "Backup folder created successfully."
  else
    echo -e "I do not have the rights to create your backup folder.\nThis script will now exit."
    exit 1
 #exit 1 is a command that exits the script with an error code
  fi
fi
#Request files to be backed up:
echo -e "\e[30mWhich files do you want backed up?\e[39m\e[49m"
read FILES
if [ -n $FILES ]
then
  cp -a $FILES $BACKUPFOLDER
else
  echo "File does not exist."
fi

لاحِظ أمر exit الّذي يُستخدَم لإيقاف السّكربت مع رمز خطأ. يعرض السّكربت رسالة عندما لا يوجد مجلّد للنّسخ الاحتيّاطيّ، عند إنشائه، إن لم يكن بالإمكان إنشاؤه، وعند كتابة سلسلة محارف خاويّة لأسماء الملفّات.

خاتمة

يضع هذا الدّرس اللّبنات الأساسيّة الّتي تمكّن من كتابة سكربتات Shell يُمكن للمستخدِم التّفاعل معها. لا زال هناك الكثير لتعلّمه من أجل كتابة برامج Shell بإمكانيّات أكبر وحلول أكثر إبداعًا، إلّا أنّ إتقان المحتوى الموجود هنا خطوة أولى في الطّريق.

ترجمة بتصرّف لسلسلة مقالات  An Introduction to Shell Scripting



3 اشخاص أعجبوا بهذا


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


شكرا

جزاكم الله خيرا

شارك هذا التعليق


رابط هذا التعليق
شارك على الشبكات الإجتماعية


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

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

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


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

تسجيل الدخول

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


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