اذهب إلى المحتوى

عندما يزداد طول البرامج وتعقيدها، فستزداد صعوبة تصميمها وبرمجتها وصيانتها؛ لذا من المفيد عادةً تقسيم المهام الكبيرة إلى سلسلة من المهام الأصغر.

سنُقسِّم في هذا الدرس السكربت الذي كنا نعمل عليه إلى عدد من الدوال (functions) المنفصلة.

shell-scripts-functions.png

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

سيبدو الوصف العام لعملية شراء الطعام كالآتي:

  1. غادر المنزل
  2. قد السيارة إلى السوق
  3. اركن السيارة
  4. ادخل السوق
  5. اشترِ طعامًا
  6. قد السيارة إلى المنزل
  7. اركن السيارة
  8. ادخل إلى المنزل

سيُغطِّي الشرح السابق الآلية العامة للذهاب إلى السوق؛ لكن تلك الكائنات الفضائية ستحتاج مزيدًا من التفاصيل، فمثلًا يمكن وصف المهمة الفرعية "اركن السيارة" كالآتي:

  1. اعثر على مكان فارغ لركن السيارة
  2. قد السيارة إلى ذاك المكان
  3. أطفئ المحرك
  4. "ارفع" المكابح اليدوية
  5. اخرج من السيارة
  6. اقفل السيارة

ويمكن بالطبع تقسيم خطوة "أطفئ المحرك" إلى عدد من الخطوات مثل:

  1. أطفئ دارة الإشعال
  2. أخرج مفتاح السيارة

وهكذا إلى أن تُفصِّل كل خطوة من كامل عملية الذهاب إلى السوق.

عملية تعريف الخطوط الأساسية ومن ثم كتابة التفاصيل لتلك الخطوات تسمى "نمط تصميم Top-Down". يسمح هذا النمط لنا بتقسيم المهام الكبيرة والضخمة إلى مهام أبسط وأصغر.

سنستخدم نمط تصميم Top-Down ليساعدنا في التخطيط لبرنامجنا الذي سنكمل تطويره وإضافة الميزات إليه.

يمكننا تلخيص "الوصف العام" للمهام التي يقوم بها السكربت الآن:

  1. بداية الصفحة
  2. بداية ترويسة الصفحة
  3. كتابة العنوان
  4. إغلاق الترويسة
  5. بداية جسم الصفحة
  6. كتابة العنوان
  7. كتابة بصمة الوقت (timestamp)
  8. إغلاق الجسم
  9. إغلاق الصفحة

تمت برمجة كل الخطوات السابقة، لكننا نريد إضافة المزيد. لندرج بعض المهام الإضافية بعد المهمة السابعة:

  1. كتابة بصمة الوقت
  2. كتابة معلومات عن إصدار النظام
  3. كتابة الوقت الذي مضى منذ آخر تشغيل (uptime)
  4. كتابة مساحة القرص
  5. كتابة المساحة التخزينية لمجلدات المنزل (home)
  6. إغلاق الجسم
  7. إغلاق الصفحة

سيكون من حسن حظنا وجود أوامر تستطيع تنفيذ المهام الإضافية، فسنستطيع استخدام "تعويض الأوامر" (command substitution) لوضعها في السكربت كالآتي:

#!/bin/bash

# sysinfo_page - A script to produce a system information HTML file

##### Constants

TITLE="System Information for $HOSTNAME"
RIGHT_NOW=$(date +"%x %r %Z")
TIME_STAMP="Updated on $RIGHT_NOW by $USER"

##### Main

cat <<- _EOF_
  <html>
  <head>
      <title>$TITLE</title>
  </head>

  <body>
      <h1>$TITLE</h1>
      <p>$TIME_STAMP</p>
      $(system_info)
      $(show_uptime)
      $(drive_space)
      $(home_space)
  </body>
  </html>
_EOF_

أما للمهام التي لا توجد أوامر تستطيع فعل ما نريد تحديدًا، فيمكننا إنشاؤها باستخدام دوال الصدفة (shell functions).

وكما تعلمنا في أحد الدروس السابقة، يمكن اعتبار دوال الصدفة على أنها "برامج صغيرة ضمن البرامج" وتسمح لنا باتباع مبادئ نمط التصميم top-down. علينا تعديل السكربت كالآتي لإضافة دوال الصدفة:

#!/bin/bash

# sysinfo_page - A script to produce an system information HTML file

##### Constants

TITLE="System Information for $HOSTNAME"
RIGHT_NOW=$(date +"%x %r %Z")
TIME_STAMP="Updated on $RIGHT_NOW by $USER"

##### Functions

system_info()
{

}


show_uptime()
{

}


drive_space()
{

}


home_space()
{

}

##### Main

cat <<- _EOF_
  <html>
  <head>
      <title>$TITLE</title>
  </head>

  <body>
      <h1>$TITLE</h1>
      <p>$TIME_STAMP</p>
      $(system_info)
      $(show_uptime)
      $(drive_space)
      $(home_space)
  </body>
  </html>
_EOF_
       

هنالك نقطتان تجدر الإشارة إليهما: أولهما أنَّه يجب تعريف دوال الصدفة قبل محاولة استخدامها؛ وثانيهما هو أنَّ جسم الدالة (أي القسم الذي يقع بين قوس البداية "}" وقوس النهاية "{") يجب أن يحتوي على أمرٍ واحدٍ على الأقل. لن يعمل السكربت السابق وسيُظهِر رسالة خطأ وذلك لأنَّ جسم الدوال فارغ. أبسط طريقة لتصحيح هذه المشكلة هي وضع عبارة "return" في جسم كل دالة، وبعدها سيُنفَّذ السكربت بنجاح.

إبقاء السكربتات قابلة للتشغيل

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

بعد إضافة الدوال إلى السكربت، أصبح بإمكانك الآن مراقبة التسلسل المنطقي لتنفيذ السكربت وذلك عبر آلية يُطلَق عليها اسم stubbing أي إضافة شيفرة وهمية. يمكنك تخيل هذه الآلية كما يلي: لنفترض أننا نريد إنشاء دالة اسمها "system_info" لكننا لم نفكر في تفاصيل الشيفرة بشكل كامل. فبدلًا من إيقاف عملية تطوير السكربت إلى أن ننتهي من الدالة system_info فيمكننا إضافة الأمر echo إليها كالآتي:

system_info()
{
    # Temporary function stub
    echo "function system_info"
}
       

سنتمكن باستخدام هذه الآلية من تنفيذ السكربت دون خطأ حتى لو لم نكمل برمجة الدالة system_info؛ ونستطيع لاحقًا وضع الشيفرة الحقيقية بدلًا من أمر echo السابق.

سبب استخدامنا لأمر echo هو أننا نحتاج إلى مؤشر لكي نعرف أنَّ السكربت قد نفَّذ الدالة المعنية.

لنُطبِّق هذه الآلية على جميع الدوال في السكربت:

#!/bin/bash

# sysinfo_page - A script to produce an system information HTML file

##### Constants

TITLE="System Information for $HOSTNAME"
RIGHT_NOW=$(date +"%x %r %Z")
TIME_STAMP="Updated on $RIGHT_NOW by $USER"

##### Functions

system_info()
{
    # Temporary function stub
    echo "function system_info"
}


show_uptime()
{
    # Temporary function stub
    echo "function show_uptime"
}


drive_space()
{
    # Temporary function stub
    echo "function drive_space"
}


home_space()
{
    # Temporary function stub
    echo "function home_space"
}


##### Main

cat <<- _EOF_
  <html>
  <head>
      <title>$TITLE</title>
  </head>

  <body>
      <h1>$TITLE</h1>
      <p>$TIME_STAMP</p>
      $(system_info)
      $(show_uptime)
      $(drive_space)
      $(home_space)
  </body>
  </html>
_EOF_

سنكمل الآن العمل على كل دالة على حدة لكي تُخرِج معلوماتٍ مفيدةً.

show_uptime

ستُظهِر الدالة show_uptime ناتج الأمر uptime، الذي يعرض عدِّة معلومات مثيرة للاهتمام حول النظام، بما في ذلك المدة الزمنية منذ آخر إعادة تشغيل، وعدد المستخدمين، والحِمل (load) الحالي على النظام.

$ uptime
9:15pm up 2 days, 2:32, 2 users, load average: 0.00, 0.00, 0.00

لعرض ناتج الأمر uptime في صفحة HTML، فسنحتاج إلى برمجة دالة الصدفة كالآتي (وذلك بعد حذف الشيفرة الوهمية التي كانت فيها):

show_uptime()
{
    echo "<h2>System uptime</h2>"
    echo "<pre>"
    uptime
    echo "</pre>"
}
  

كما ترى، تُخرِج الدالة السابقة نصًا يحتوي على خليطٍ من وسوم HTML مع مخرجات الأمر uptime؛ وستصبح هذه المخرجات جزءًا من here script عندما تُجرى عملية "تعويض الأوامر" في الجزء الرئيسي من السكربت.

drive_space

تستخدم الدالة drive_space الأمر df لتوفير ملخص للمساحة التخزينية المستهلكة من أنظمة الملفات الموصولة (mounted file systems).

$ df

Filesystem   1k-blocks      Used Available Use% Mounted on

/dev/hda2       509992    225772    279080  45% /
/dev/hda1        23324      1796     21288   8% /boot
/dev/hda3     15739176   1748176  13832360  12% /home
/dev/hda5      3123888   3039584     52820  99% /usr

ستبدو بنية دالة dive_space شبيهةً للغاية بدالة show_uptime:

drive_space()
{
    echo "<h2>Filesystem space</h2>"
    echo "<pre>"
    df
    echo "</pre>"
}

home_space

ستُظهِر دالة home_space مقدار المساحة التخزينية التي يستهلكها كل مستخدم في مجلد المنزل الخاص به. سيُعرَض الناتج كقائمة مرتبة تنازليًا وفق مقدار المساحة التخزينية المستخدمة.

home_space()
{
    echo "<h2>Home directory space by user</h2>"
    echo "<pre>"
    echo "Bytes Directory"
    du -s /home/* | sort -nr
    echo "</pre>"
}

لاحظ أنَّه يجب تنفيذ السكربت عبر مستخدم يملك امتيازات إدارية لكي تعمل الدالة السابقة بشكلٍ صحيح، لأنَّ الأمر du يتطلب امتيازات الجذر (root) لكي يتفحص محتويات المجلد ‎/home.

system_info

لسنا جاهزين بعد لإكمال دالة system_info. لكننا سنُحسِّن من الشيفرة الوهمية التي فيها لكي تُنتِج وسوم HTML:

system_info()
{
    echo "<h2>System release info</h2>"
    echo "<p>Function not yet implemented</p>"
}
  

ترجمة -وبتصرّف- للمقالَين Shell Functions و Some Real Work لصاحبهما William Shotts.


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

أفضل التعليقات

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



انضم إلى النقاش

يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.

زائر
أضف تعليق

×   لقد أضفت محتوى بخط أو تنسيق مختلف.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   جرى استعادة المحتوى السابق..   امسح المحرر

×   You cannot paste images directly. Upload or insert images from URL.


×
×
  • أضف...