الأخطاء والإشارات والتعامل معها في سكربتات الصدفة (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. استخدام غير صحيح للمتغيرات
قد يؤدي استخدام متغير غير مُعرف إلى حدوث أخطاء غير متوقعة، خاصة في العمليات الحسابية أو عمليات المسارات.
bashecho "المسار هو: $PATH_VAR" # إذا لم يكن معرفاً، ستكون النتيجة فارغة
2. التعامل مع الملفات
أخطاء مثل عدم وجود الملف، أو عدم وجود صلاحيات للقراءة أو الكتابة عليه، هي من أكثر الأخطاء شيوعاً.
bashif [ ! -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. تضمين رسائل الخطأ في السجلات
يمكن إعادة توجيه الأخطاء إلى ملفات سجل لمتابعتها لاحقاً:
bashcp /file /backup/ 2>> /var/log/script_errors.log
3. دمج المخرجات القياسية والخطأ
في بعض الحالات، قد يكون من المفيد توجيه كل المخرجات إلى ملف واحد:
bashcommand &> 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.

