Bash/developing good scripts
تطوير برامج Bash جيدة
خصائص الشيفرات الجيدة
هذا الشرح عن آخر وحدة بناء للصدفة وهي الشيفرات النصية. إليك بعض الأمور التي يجب أن تراعيها قبل أن نكمل:
- يجب أن تعمل الشيفرة بدون أخطاء.
- يجب أن تنفذ المهمة التي كُتبت لها.
- يجب أن يكون منطق البرنامج محددًا وظاهرًا.
- لا تنفذ الشيفرة مهامًا غير ضرورية.
- ينبغي أن تكون الشيفرة قابلة لإعادة استخدامها.
الهيكل Structure
يجب أن يكون هيكل شيفرة الصدفة مرنًا للغاية، فرغم أن bash بها حرية ظاهرة، إلا أنه يجب تحقيق منطق صحيح وتحكم في التدفق والكفاءة بحيث يستطيع المستخدم تنفيذ الشيفرة بشكل صحيح وبسهولة، ولضمان ذلك، سل نفسك هذه الأسئلة حين تكتب شيفرة نصية جديدة:
- هل سأحتاج أي بيانات من المستخدم أو من بيئته؟
- كيف سأخزِّن تلك البيانات؟
- هل هناك أي ملفات يجب إنشاؤها؟ وإن كان فأين يجب إنشاؤها وما الأذونات المناسبة لها، ومن المستخدم الذي سيعطَى ملكيتَها؟
- ما الأوامر التي سأستخدمها؟ وهل تملك أنظمةُ التشغيل التي ستعمل عليها الشيفرةُ تلك الأوامر بإصداراتها المناسبة؟
- هل يحتاج المستخدم أي إشعارات؟ متى ولماذا؟
الاصطلاح Terminology
يعطي الجدول التالي نظرة عامة عن المصطلحات البرمجية التي ينبغي أن تفهمها جيدًا:
جدول 1-1: نظرة عامة على المصطلحات البرمجية
المصطلح | الوصف |
التحكم في الأمر (command control) | اختبار حالة الخروج للأمر لتحديد ما إن كان يجب تنفيذ جزء معين من البرنامج أم لا. |
التفرع الشرطي (conditional branch) | نقطة منطقية في البرنامج، يحدِّد فيها شرط ما الخطوة التالية |
التدفق المنطقي (logic flow) | التصميم العام للبرنامج، ويحدد التسلسل المنطقي للمهام لضمان نتيجة ناجحة ومحددة. |
الحلقة التكرارية (loop) | جزء من البرنامج يتم تنفيذه "س" مرة، حيث س تساوي صفر أو أكثر. |
مدخلات المستخدم (user input) | البيانات التي يتم إدخالها بواسطة مصدر خارجي أثناء عمل البرنامج، ويمكن تخزينها واستدعاءها عند الحاجة. |
النظام والترتيب أولًا
أول خطوة في عملية تطوير شيفرة نصية هي ترتيب الخطوات المنطقية للبرنامج مسبقًا من أجل تسريع عملية تطويره. وإحدى الوسائل المشهورة في ذلك هي استخدام قوائم بالمهام التي سينفذها البرنامج مرتبة في عناصر، فذلك يسمح لك بوصف كل عملية على حدة، كما يمكن الإشارة إلى كل مهمة باستخدام رقم ترتيبها في القائمة.
استخدم لغتك التي تتحدث بها في وصف المهام التي سينفذها برنامجك كي تنشئ صورة مفهومة عنه، ثم تستطيع بعدها استبدال أوامر الصدفة وكلماتها بما وصفته بلغتك العادية.
ويقدم الشرح الآتي مثالًا عن تصميم منطقي لتنفيذ أوامر برنامج يصف دورانًا لملفات السجل (log files)، فيعرض احتمالًا لحلقة تكرارية (loop) يُتحكَّم بها عن طريق عدد ملفات السجل الأساسية التي تريد تدويرها:
- هل تريد تدوير السجلات؟
- في حالة نعم:
- أدخل اسم المجلد الذي يحتوي السجلات التي تريد تدويرها.
- أدخل الاسم الأساسي لملف السجل.
- أدخل عدد الأيام التي يجب أن تُحفظ سجلاتُها.
- ثبِّت الإعدادات بجعلها دائمة في ملف crontab الخاص بالمستخدم.
- في حالة لا: اذهب إلى خطوة 3.
- في حالة نعم:
- هل تريد تدوير مجموعة أخرى من السجلات؟
- في حالة نعم: كرر خطوة 1.
- في حالة لا: اذهب إلى خطوة 3.
- اخرج.
ينبغي أن يقدم المستخدم بيانات للبرنامج كي يتصرف، ويجب أن تُسجل مدخلات المستخدم وتُحفظ، ويُرسل إشعار إلى المستخدم أن ملف crontab الخاص به ستحدث به تغييرات.
مثال لشيفرة نصية: mysystem.sh
تُنفذ شيفرة mysystem.sh
بالأسفل بعض الأوامر المشهورة (date
، w
، uname
، uptime
) من أجل عرض بعض البيانات عنك وعن حاسوبك.
hsoub:~> cat -n mysystem.sh
1 #!/bin/bash
2 clear
3 echo "This is information provided by mysystem.sh. Program starts now."
4
5 echo "Hello, $USER"
6 echo
7
8 echo "Today's date is `date`, this is week `date +"%V"`."
9 echo
10
11 echo "These users are currently connected:"
12 w | cut -d " " -f 1 - | grep -v USER | sort -u
13 echo
14
15 echo "This is `uname -s` running on a `uname -m` processor."
16 echo
17
18 echo "This is the uptime information:"
19 uptime
20 echo
21
22 echo "That's all folks!"
تبدأ الصدفة دومًا بنفس المَحرَفيْن !#
ثم تُحدَّد الصدفة التي ستنفذ الأوامر التي سيأتي ذكرها بعد السطر الأول كما يلي:
- بدأت الشيفرة أعلاه في سطر رقم 2 بمسح الأوامر الموجودة على الشاشة.
- سطر 3 يطبع رسالة تخبر المستخدم عما سيحدث.
- سطر 5 يحيِّي المستخدم.
- الأسطر 6 و 9 و 13 و 16 و 20 موجودة من أجل الحفاظ على شكل منظم لمُخرجات الأمر.
- يطبع سطر 8 التاريخ الحالي ورقم الأسبوع.
- سطر 11 يطبع رسالة بها معلومات للمستخدم، تمامًا كسطر 3 و18 و22.
- يهيئ سطر 12 خرج أمر w.
- يعرض سطر 15 بيانات عن نظام التشغيل والمعالج.
- يعرض سطر 19 بيانات وقت التشغيل والأحمال.
وبالنسبة لأمريْ echo
و printf
فكلاهما أمر مضمَّن في bash، يخرج أولهما دومًا بحالة 0، ويطبع وسائط (arguments) متبوعة بمحرف نهاية السطر على الخرج العادي، في حين يسمح الثاني بتحديد نص تهيئة (formatting string) ويعطي حالة خروج غير صفرية عند الفشل.
إليك نفس الشيفرة باستخدام أمر printf
:
hsoub:~> cat -n mysystem.sh
1 #!/bin/bash
2 clear
3 echo "This is information provided by mysystem.sh. Program starts now."
4
5 echo "Hello, $USER"
6 echo
7
8 echo "Today's date is `date`, this is week `date +"%V"`."
9 echo
10
11 echo "These users are currently connected:"
12 w | cut -d " " -f 1 - | grep -v USER | sort -u
13 echo
14
15 echo "This is `uname -s` running on a `uname -m` processor."
16 echo
17
18 echo "This is the uptime information:"
19 uptime
20 echo
21
22 echo "That's all folks!"
انظر كتابة برامج bash تفاعلية للمزيد عن إنشاء شيفرات نصية صديقة للمستخدم (user friendly) من حيث إدخاله للرسائل.
المسار الافتراضي لصدفة bash
هذا يفترض أن برنامج bash مثبَّت في bin/.
إن لم يكن stdout متاحًا
إن نفَّذت شيفرة من cron، فاكتب أسماء المسارات الكاملة وأعد توجيه الخرج والأخطاء، ذلك أن أية خطأ قد يُغلق الصدفة قبل الوقت المحدد بما أن الصدفة تعمل في وضع غير تفاعلي.
مثال لشيفرة init
تبدأ شيفرة init خدمات النظام على حواسيب يونكس ولينكس مثل عفريت سجل النظام (system log daemon) وعفريت إدارة الطاقة وعفاريت الاسم والبريد، فتلك الشيفرات التي تُعرف أيضًا بشيفرات بدء التشغيل مخزَّنة في أماكن محددة في النظام، مثل etc/rc.d/init.d/
أو etc/init.d/
.
تقرأ العملية الأولى init ملفات إعداداتها لتقرر أي الخدمات التي يجب تشغيلها وإيقافها في كل مستوى تشغيل. ومستوى التشغيل هو سلسلة مرتبة من العمليات، وكل نظام به مستوى تشغيل وحيد للمستخدم (user run level) لتنفيذ مهام إدارية مثلًا يكون النظام خلالها غير مستخدم بقدر الإمكان، مثل استعادة نظام ملفات (file system) من نسخة احتياطية. أيضًا، فإن مستويات تشغيل Reboot و shutdown يتم إعدادهما كذلك.
وتُسرد المهام التي يجب تنفيذها عند تشغيل خدمة أو إيقافها في شيفرات بدء التشغيل، وتلك إحدى مهام مدير النظم أن يضبط إعدادات init بحيث تبدأ الخدمات وتتوقف في التوقيت الصحيح. ويجب أن يكون لديك فهم جيد لإجراءات التشغيل والإيقاف على نظامك، لذا ننصح أن تقرأ صفحات man
لـ init وinittab قبل البدء في شيفرات التهيئة (initialization scripts) الخاصة بك.
إليك مثالًا بسيطًا يجب أن يشغِّل صوتًا عند تشغيل وإيقاف حاسوبك:
#!/bin/bash
# This script is for /etc/rc.d/init.d
# Link in rc3.d/S99audio-greeting and rc0.d/K01audio-greeting
case "$1" in
'start')
cat /usr/share/audio/at_your_service.au > /dev/audio
;;
'stop')
cat /usr/share/audio/oh_no_not_again.au > /dev/audio
;;
esac
exit 0
ستجد تفصيلًا عن عبارة case
التي تُستخدم عادة في مثل ذلك النوع من الشيفرات في استخدامات if المتقدمة في bash.
ملخص
Bash هي صدفة نظام جنو التي تتوافق مع صدفة بورن وتزيد عليها بعدة مزايا وخصائص مفيدة من باقي الصدفات، وحين تبدأ الصدفة فإنها تقرأ ملفات إعداداتها، وأهم تلك الملفات ما يلي:
etc/profile/
bash_profile~/.
bashrc~/.
وتتصرف bash بشكل مختلف حين تكون في وضع تفاعلي، وكذلك فإنها متوافقة مع معايير POSIX وبها وضع محظور. ويمكن تقسيم أوامرها إلى ثلاث مجموعات: دوال الصدفة والأوامر المُضمَّنة والأوامر الموجودة داخل مجلد في نظامك. وكذلك تدعم bash أوامر مضمَّنة أخرى ليست موجودة داخل صدفة بورن الأصلية.
وتتكون الشيفرات النصية (shell scripts) من تلك الأوامر مرتبة كما تحددها قوانين الصدفة، وتُقرأ تلك الشيفرات وتُنفَّذ سطرًا سطرًا، ويجب أن تكون هيكلتها منطقية.