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