كيفية اعتراض الأخطاء في نصوص Bash على نظام Linux

نشرت: 2022-08-27
كمبيوتر محمول Linux يعرض موجه bash
fatmawati achmad zaenuri / Shutterstock.com

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

معالجة الخطأ في البرامج النصية

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

تخصيص أخطاء التحقق من صحة المعلمة في PowerShell
ذات الصلة بأخطاء التحقق من صحة المعلمة في PowerShell

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

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

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

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

كشف حالة الخروج

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

يمكننا التحقق من حالة الخروج - المعروفة أيضًا باسم كود الإرجاع - للأوامر التي يستخدمها البرنامج النصي ، وتحديد ما إذا كان الأمر ناجحًا أم لا.

في Bash ، الصفر يساوي true. إذا كانت الاستجابة من الأمر غير صحيحة ، فنحن نعلم حدوث مشكلة ويمكننا اتخاذ الإجراء المناسب.

انسخ هذا النص في محرر ، واحفظه في ملف يسمى “bad_command.sh.”

 #! / بن / باش

إذا (! bad_command) ؛ ومن بعد
  صدى "وضع علامة bad_command على خطأ."
  خروج 1
فاي

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

 chmod + x bad_command.sh 

جعل النص قابل للتنفيذ باستخدام chmod

عندما نقوم بتشغيل البرنامج النصي نرى رسالة الخطأ المتوقعة.

 ./bad_command.sh 

التحقق من حالة خروج الأمر لتحديد ما إذا كان هناك خطأ

لا يوجد أمر مثل "bad_command" ، ولا هو اسم دالة داخل البرنامج النصي. لا يمكن تنفيذه ، لذا فإن الاستجابة ليست صفرًا. إذا لم تكن الإجابة صفرًا - يتم استخدام علامة التعجب هنا كعامل NOT المنطقي - يتم تنفيذ نص عبارة if .

في نص برمجي حقيقي ، يمكن أن يؤدي هذا إلى إنهاء النص ، وهو ما يفعله مثالنا ، أو قد يحاول معالجة حالة الخطأ.

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

يمكنك استخدام عامل التشغيل المنطقي OR مع حالة الخروج لأمر ما ، واستدعاء أمر آخر أو وظيفة في البرنامج النصي الخاص بك إذا كانت هناك استجابة غير صفرية من الأمر الأول.

 command_1 || الأمر_2

يعمل هذا لأن الأمر الأول يتم تشغيله OR الثاني. يتم تشغيل الأمر الموجود في أقصى اليسار أولاً. إذا نجح الأمر الثاني فلن يتم تنفيذه. ولكن إذا فشل الأمر الأول ، فسيتم تنفيذ الأمر الثاني. لذلك يمكننا هيكلة كود مثل هذا. هذا هو "logical-or./sh."

 #! / بن / باش

معالج الأخطاء()
{
  صدى "خطأ: ($؟) $ 1"
  خروج 1
}

أمر سيء || error_handler "فشل bad_command ، السطر: $ {LINENO}"

لقد حددنا وظيفة تسمى error_handler . هذا يطبع حالة الخروج من الأمر الفاشل ، المحفوظة في المتغير $? وسطر نص يتم تمريره إليه عند استدعاء الوظيفة. يتم الاحتفاظ بهذا في المتغير $1 . تقوم الوظيفة بإنهاء البرنامج النصي بحالة خروج واحدة.

يحاول البرنامج النصي تشغيل bad_command والذي من الواضح أنه فشل ، لذا فإن الأمر الموجود على يمين عامل التشغيل المنطقي OR ، || ، يتم تنفيذ. هذا يستدعي الدالة error_handler ويمرر سلسلة تسمي الأمر الذي فشل ، ويحتوي على رقم سطر الأمر الفاشل.

سنقوم بتشغيل البرنامج النصي لرؤية رسالة معالج الخطأ ، ثم التحقق من حالة الخروج من البرنامج النصي باستخدام echo.

 ./logical-or.sh
 صدى $؟ 

استخدام عامل التشغيل المنطقي OR لاستدعاء معالج الأخطاء في نص برمجي

توفر وظيفة error_handler الصغيرة لدينا حالة الخروج لمحاولة تشغيل bad_command واسم الأمر ورقم السطر. هذه معلومات مفيدة عندما تقوم بتصحيح برنامج نصي.

حالة الخروج من البرنامج النصي واحدة. تعني حالة الخروج 127 التي تم الإبلاغ عنها بواسطة error_handler "الأمر غير موجود". إذا أردنا ، يمكننا استخدام ذلك كحالة الخروج من البرنامج النصي عن طريق تمريره إلى الأمر exit .

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

 exit_code = $؟

إذا [$ exit_code -eq 1] ؛ ومن بعد
  صدى "العملية غير مسموح بها"

elif [$ exit_code -eq 2] ؛ ومن بعد
  صدى "إساءة استخدام شل البنايات"
.
.
.
elif [$ status -eq 128]؛ ومن بعد
  صدى "وسيطة غير صالحة"
فاي

باستخدام مجموعة لفرض الخروج

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

للقيام بذلك ، استخدم الأمر set مع خيار -e (خطأ). يخبر هذا البرنامج النصي بالخروج كلما فشل الأمر أو أعاد رمز خروج أكبر من الصفر. كما أن استخدام الخيار -E يضمن عمل اكتشاف الأخطاء والملاءمة في وظائف الصدفة.

كيفية استخدام set and pipefail في Bash Scripts على Linux
ذات صلة كيفية استخدام set and pipefail في Bash Scripts على Linux

للقبض على المتغيرات غير المهيأة أيضًا ، أضف الخيار -u (unset). للتأكد من اكتشاف الأخطاء في تسلسلات الأنابيب ، أضف الخيار -o pipefail . بدون ذلك ، تكون حالة الخروج من تسلسل الأوامر عبر الأنابيب هي حالة الخروج للأمر الأخير في التسلسل. لن يتم الكشف عن أمر فاشل في منتصف تسلسل الأنابيب. يجب أن يأتي الخيار -o pipefail في قائمة الخيارات.

التسلسل المراد إضافته إلى الجزء العلوي من البرنامج النصي هو:

 مجموعة -Eeuo pipefail

هذا نص قصير يسمى “unset-var.sh” ، مع متغير غير محدد فيه.

 #! / بن / باش

مجموعة -Eeou pipefail

صدى "$ unset_variable"

صدى "هل نرى هذا الخط؟"

عندما نقوم بتشغيل البرنامج النصي ، يتم التعرف على unset_variable كمتغير غير مهيأ ويتم إنهاء البرنامج النصي.

 ./unset-var.sh 

استخدام الأمر set في برنامج نصي لإنهاء البرنامج النصي في حالة حدوث خطأ

لا يتم تنفيذ أمر echo الثاني أبدًا.

استخدام المصيدة مع الأخطاء

يتيح لك الأمر Bash trap تسمية أمر أو وظيفة ينبغي استدعاؤها عند رفع إشارة معينة. عادةً ما يتم استخدام هذا لالتقاط إشارات مثل SIGINT التي يتم رفعها عند الضغط على مجموعة المفاتيح Ctrl + C. هذا البرنامج النصي هو "sigint.sh."

 #! / بن / باش

اعتراض "echo -e '\ n تم إنهاؤه بواسطة Ctrl + c' ؛ قم بإنهاء" SIGINT

العداد = 0

احيانا صحيح
فعل 
  صدى "رقم الحلقة:" $ ((عداد ++))
  النوم 1
فعله

يحتوي الأمر trap على أمر echo وأمر exit . سيتم تشغيله عند رفع SIGINT . باقي النص عبارة عن حلقة بسيطة. إذا قمت بتشغيل البرنامج النصي وضغطت على Ctrl + C ، فسترى الرسالة من تعريف trap ، وسيتم إنهاء البرنامج النصي.

 ./sigint.sh 

استخدام trap في نص برمجي للقبض على Ctrl + c

يمكننا استخدام trap مع إشارة ERR للقبض على الأخطاء عند حدوثها. يمكن بعد ذلك إطعامها إلى أمر أو وظيفة. هذا هو "trap.sh." نحن نرسل إعلامات خطأ إلى وظيفة تسمى error_handler .

 #! / بن / باش

اعتراض 'error_handler $؟ خطأ $ LINENO

معالج الأخطاء() {
  صدى "خطأ: ($ 1) حدث في $ 2"
}

رئيسي() {
  صدى "داخل الوظيفة الرئيسية ()"
  أمر سيء
  ثانيا
  الثالث
  الخروج $؟
}

ثانيا() {
  صدى "بعد استدعاء main ()"
  صدى "داخل الثانية () وظيفة"
}

الثالث() {
  صدى "داخل الوظيفة () الثالثة"
}

رئيسي

يقع الجزء الأكبر من النص داخل الوظيفة main ، والتي تستدعي الوظيفتين second third . عند مواجهة خطأ - في هذه الحالة ، بسبب عدم وجود bad_command - تقوم عبارة trap بتوجيه الخطأ إلى دالة error_handler . يقوم بتمرير حالة الخروج من الأمر الفاشل ورقم السطر إلى وظيفة error_handler .

 ./trap.sh 

استخدام التراكب مع ERR للقبض على الأخطاء في البرنامج النصي

تقوم وظيفة error_handler تفاصيل الخطأ في النافذة الطرفية. إذا أردت ، يمكنك إضافة أمر exit إلى الوظيفة لإنهاء البرنامج النصي. أو يمكنك استخدام سلسلة من عبارات if/elif/fi لتنفيذ إجراءات مختلفة لأخطاء مختلفة.

قد يكون من الممكن معالجة بعض الأخطاء ، والبعض الآخر قد يتطلب توقف البرنامج النصي.

نصيحة أخيرة

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

إذا كنت تستخدم هذا الأمر لتشغيل البرنامج النصي الخاص بك ، فسوف يعرض لك Bash إخراج التتبع أثناء تنفيذ البرنامج النصي:

 bash -x your-script.sh

يكتب Bash إخراج التتبع في النافذة الطرفية. يعرض كل أمر مع وسيطاته - إذا كان يحتوي على أي منها. يحدث هذا بعد توسيع الأوامر ولكن قبل تنفيذها.

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

ذات صلة: كيفية التحقق من صحة بناء جملة نص Linux Bash قبل تشغيله