ديف أوبس

التعامل مع الأخطاء في الشيل

الأخطاء والإشارات والتعامل معها في سكربتات الصدفة (Shell Scripts)

تُعد سكربتات الصدفة (Shell Scripts) أداةً فعالة في أتمتة المهام ضمن أنظمة التشغيل القائمة على يونكس ولينكس. ومع تزايد اعتماد المستخدمين والمطورين على هذه السكربتات، تبرز الحاجة إلى فهم عميق لكيفية التعامل مع الأخطاء والإشارات (Signals) ضمنها، حيث تُشكّل هذه العناصر عصب الأمان والاستقرار لأي نظام برمجي يُعتمد عليه في تنفيذ العمليات الحرجة أو المتكررة.

هذا المقال الموسع يسلط الضوء على مفهوم الأخطاء، أنواعها، كيفية إدارتها، بالإضافة إلى الإشارات ومعالجتها في سياق السكربتات المكتوبة بلغة Bash، وهي الصدفة الأكثر استخداماً في أنظمة لينكس.


أولاً: فهم الأخطاء في سكربتات الصدفة

1. تعريف الخطأ في سياق الصدفة

الخطأ في سكربتات الصدفة لا يعني بالضرورة حدوث خلل كارثي، بل هو ببساطة قيمة الإرجاع (Exit Status) التي تختلف عن القيمة “0”.

القيمة 0 تعني عادةً نجاح الأمر، بينما أي قيمة غير ذلك تشير إلى نوع معين من الفشل. يمكن للأوامر إرجاع أكواد محددة تتعلق بنوع الخطأ، مثل:

كود الخروج المعنى
0 نجاح الأمر
1 خطأ عام
2 سوء استخدام للأوامر المضمنة أو خيار غير صالح
126 الأمر غير قابل للتنفيذ
127 الأمر غير موجود
130 تم مقاطعة الأمر (مثل SIGINT)
137 قتل العملية باستخدام إشارة (مثل SIGKILL)

هذه الأكواد تُمكّن المطور من تحليل ما حدث واتخاذ الإجراءات المناسبة.


ثانياً: التعامل مع الأخطاء

1. استخدام set -e

عند استخدام الأمر set -e في بداية السكربت، يُطلب من Bash أن يُنهي تنفيذ السكربت فور حدوث أي خطأ (أي أمر يُرجع كود خروج ≠ 0). هذا السلوك يُعتبر مفيداً في ضمان عدم متابعة السكربت تنفيذ أوامر بعد فشل أحدها.

bash
#!/bin/bash set -e cp /source/file /destination/ echo "تم النسخ بنجاح"

2. استخدام set -u

يُستخدم هذا الخيار لإنهاء السكربت في حال استخدام متغير غير مُعرف. وهذا يساعد في تقليل الأخطاء الناتجة عن الأخطاء الإملائية أو نسيان تعريف متغير.

bash
#!/bin/bash set -u echo "اسم المستخدم هو: $USERNAME"

3. التعامل اليدوي مع أكواد الخروج

يمكن التحقق من نجاح أو فشل أمر معين باستخدام متغير $? الذي يحتوي على كود الخروج لآخر أمر تم تنفيذه.

bash
#!/bin/bash cp /source/file /destination/ if [ $? -ne 0 ]; then echo "فشل النسخ" exit 1 fi

4. استخدام trap لتنفيذ إجراءات عند الخطأ

trap تُستخدم للتقاط الأخطاء أو الإشارات وتنفيذ إجراءات معينة عند حدوثها. على سبيل المثال، لتنظيف ملفات مؤقتة عند حدوث خطأ:

bash
#!/bin/bash trap 'echo "حدث خطأ. تنظيف الملفات..."; rm -f /tmp/tempfile' ERR set -e touch /tmp/tempfile cp /nonexistent/file /tmp/

ثالثاً: أنواع الأخطاء الشائعة في سكربتات الصدفة

1. استخدام غير صحيح للمتغيرات

قد يؤدي استخدام متغير غير مُعرف إلى حدوث أخطاء غير متوقعة، خاصة في العمليات الحسابية أو عمليات المسارات.

bash
echo "المسار هو: $PATH_VAR" # إذا لم يكن معرفاً، ستكون النتيجة فارغة

2. التعامل مع الملفات

أخطاء مثل عدم وجود الملف، أو عدم وجود صلاحيات للقراءة أو الكتابة عليه، هي من أكثر الأخطاء شيوعاً.

bash
if [ ! -f "$filename" ]; then echo "الملف غير موجود" exit 1 fi

3. استخدام غير صحيح للتكرار أو الشروط

مثلاً، استخدام خاطئ لجمل if أو for أو نسيان الأقواس المناسبة قد يسبب توقف السكربت أو تنفيذ أوامر غير متوقعة.


رابعاً: فهم الإشارات (Signals) والتعامل معها

1. ما هي الإشارات في لينكس؟

الإشارات هي وسيلة يتواصل بها النظام مع العمليات لإعلامها بحدث معين مثل الإنهاء أو الإيقاف المؤقت أو المقاطعة. تستخدم بشكل واسع في إدارة العمليات.

2. إشارات شائعة في الصدفة

الإشارة الرقم الوصف
SIGINT 2 مقاطعة (Ctrl+C)
SIGTERM 15 إنهاء ناعم للعملية
SIGKILL 9 قتل فوري لا يمكن تجاهله
SIGHUP 1 انقطاع الاتصال بالجلسة
SIGQUIT 3 خروج وتفريغ النواة

3. استخدام trap لالتقاط الإشارات

تُعتبر trap من الأدوات الفعالة جداً في التعامل مع الإشارات، حيث يمكن من خلالها تحديد إجراءات تُنفذ عند استقبال إشارات محددة.

bash
#!/bin/bash trap 'echo "تم إيقاف السكربت بواسطة SIGINT"; exit 130' SIGINT while true; do echo "تشغيل..." sleep 1 done

4. حالات استخدام واقعية للإشارات

  • تنظيف الملفات المؤقتة عند الخروج القسري.

  • إغلاق الاتصالات أو الملفات المفتوحة بأمان.

  • إيقاف الحلقات اللانهائية بشكل آمن عند تلقي إشارة إنهاء.


خامساً: آليات متقدمة للتعامل مع الخطأ

1. استخدام الدوال مع فحص الأخطاء

تُعتبر الدوال طريقة منظمة لإدارة الأخطاء. يمكن أن تُرجع الدالة كود خروج خاص بها ويتم التعامل معه بناءً على السياق.

bash
نسخ_ملف() { cp "$1" "$2" if [ $? -ne 0 ]; then echo "فشل نسخ $1 إلى $2" return 1 fi } نسخ_ملف "/file1" "/backup/"

2. تضمين رسائل الخطأ في السجلات

يمكن إعادة توجيه الأخطاء إلى ملفات سجل لمتابعتها لاحقاً:

bash
cp /file /backup/ 2>> /var/log/script_errors.log

3. دمج المخرجات القياسية والخطأ

في بعض الحالات، قد يكون من المفيد توجيه كل المخرجات إلى ملف واحد:

bash
command &> all_output.log

سادساً: مثال شامل مع معالجة الأخطاء والإشارات

bash
#!/bin/bash # إعداد خيارات الحماية set -euo pipefail trap 'echo "تم استقبال SIGINT. إنهاء آمن..."; exit 1' SIGINT trap 'echo "حدث خطأ في السطر رقم $LINENO"; exit 1' ERR # تعريف دالة نسخ_آمن() { local src=$1 local dest=$2 if [ ! -f "$src" ]; then echo "الملف $src غير موجود" return 1 fi cp "$src" "$dest" echo "تم النسخ من $src إلى $dest" } # تنفيذ mkdir -p /tmp/backup نسخ_آمن "/etc/passwd" "/tmp/backup/" نسخ_آمن "/etc/shadow" "/tmp/backup/"

سابعاً: استخدام الجداول في رصد الأخطاء والإشارات

الجدول التالي يلخص أهم الإشارات والأوامر المفيدة في التعامل مع الأخطاء:

العنصر الغرض الأمر / الاستخدام
set -e إنهاء السكربت عند أول خطأ set -e
set -u إنهاء السكربت عند متغير غير معرف set -u
trap تنفيذ إجراء عند خطأ أو إشارة trap '...' ERR
exit إنهاء السكربت بقيمة محددة exit 1
$? آخر كود خروج if [ $? -ne 0 ]; then ...
SIGINT إشارة إيقاف (مثل Ctrl+C) trap '...' SIGINT
SIGTERM إشارة إنهاء آمنة trap '...' SIGTERM
2> إعادة توجيه الخطأ إلى ملف command 2> error.log

الخلاصة

التعامل مع الأخطاء والإشارات في سكربتات الصدفة ليس مجرد جانب تقني إضافي، بل هو جزء أساسي من تصميم سكربتات آمنة، مستقرة وفعالة. تجاهل التعامل مع حالات الفشل أو إشارات النظام قد يؤدي إلى نتائج غير متوقعة، وفقدان بيانات، أو حتى توقف النظام في حالات حرجة. من خلال فهم آليات مثل trap، set -e, و exit status، يمكن للمطور كتابة سكربتات عالية الجودة وقابلة للصيانة.

المصادر والمراجع:

  • Advanced Bash-Scripting Guide, Mendel Cooper.

  • GNU Bash Reference Manual, Free Software Foundation.