كيفية استخدام set and pipefail في Bash Scripts على Linux
نشرت: 2022-06-25 تحدد أوامر set
Linux و pipefail
ما يحدث عند حدوث فشل في برنامج Bash النصي. هناك الكثير لتفكر فيه أكثر مما ينبغي أن يتوقف أو ينبغي أن يستمر.
ذات صلة: دليل المبتدئين إلى البرمجة النصية للقذيفة: الأساسيات
نصوص باش وشروط الخطأ
نصوص Bash shell رائعة. إنهم سريعون في الكتابة ولا يحتاجون إلى تجميع. يمكن تغليف أي إجراء متكرر أو متعدد المراحل تحتاج إلى تنفيذه في نص مناسب. ونظرًا لأن البرامج النصية يمكنها استدعاء أي من أدوات Linux المساعدة القياسية ، فأنت لست مقيدًا بإمكانيات لغة shell نفسها.
ولكن يمكن أن تنشأ المشاكل عند استدعاء أداة خارجية أو برنامج. إذا فشلت ، ستغلق الأداة المساعدة الخارجية وترسل رمز إرجاع إلى shell ، وقد تطبع رسالة خطأ إلى الجهاز. لكن البرنامج النصي الخاص بك سيستمر في المعالجة. ربما لم يكن هذا ما تريده. إذا حدث خطأ في وقت مبكر من تنفيذ البرنامج النصي ، فقد يؤدي ذلك إلى مشكلات أسوأ إذا تم السماح بتشغيل بقية البرنامج النصي.
يمكنك التحقق من رمز الإرجاع من كل عملية خارجية عند اكتمالها ، ولكن يصبح ذلك صعبًا عندما يتم نقل العمليات إلى عمليات أخرى. سيكون رمز الإرجاع من العملية في نهاية الأنبوب ، وليس من العملية التي فشلت في المنتصف. بالطبع ، يمكن أن تحدث أخطاء داخل البرنامج النصي أيضًا ، مثل محاولة الوصول إلى متغير غير مهيأ.
يتيح لك الأمران set
و pipefile
تحديد ما يحدث عند حدوث أخطاء مثل هذه. كما أنها تتيح لك اكتشاف الأخطاء حتى عند حدوثها في منتصف سلسلة الأنابيب.
إليك كيفية استخدامها.
إظهار المشكلة
هذا نص تافه باش. إنه يردد سطرين من النص إلى المحطة. يمكنك تشغيل هذا البرنامج النصي إذا قمت بنسخ النص في محرر وحفظه باسم "script-1.sh."
#! / بن / باش صدى هذا سيحدث أولاً صدى هذا سيحدث ثانيا
لجعله قابلاً للتنفيذ ، ستحتاج إلى استخدام chmod
:
chmod + x script-1.sh
ستحتاج إلى تشغيل هذا الأمر على كل برنامج نصي إذا كنت تريد تشغيلها على جهاز الكمبيوتر الخاص بك. لنقم بتشغيل البرنامج النصي:
./script-1.sh
يتم إرسال سطري النص إلى النافذة الطرفية كما هو متوقع.
دعونا نعدل البرنامج النصي قليلا. سنطلب من ls
سرد تفاصيل ملف غير موجود. هذا سوف يفشل. لقد حفظنا هذا كـ "script-2.sh" وجعلناه قابلاً للتنفيذ.
#! / بن / باش صدى هذا سيحدث أولاً ls اسم ملف وهمي صدى هذا سيحدث ثانيا
عندما نقوم بتشغيل هذا البرنامج النصي ، نرى رسالة الخطأ من ls
.
./script-2.sh
على الرغم من فشل الأمر ls
، استمر تشغيل البرنامج النصي. وعلى الرغم من حدوث خطأ أثناء تنفيذ البرنامج النصي ، فإن كود الإرجاع من البرنامج النصي إلى الصدفة هو صفر ، مما يشير إلى النجاح. يمكننا التحقق من ذلك باستخدام echo و $?
المتغير الذي يحمل آخر كود إرجاع تم إرساله إلى الصَدَفة.
صدى $؟
الصفر الذي يتم الإبلاغ عنه هو رمز الإرجاع من الارتداد الثاني في البرنامج النصي. إذن هناك مشكلتان في هذا السيناريو. الأول هو أن البرنامج النصي به خطأ ولكنه استمر في العمل. يمكن أن يؤدي ذلك إلى مشاكل أخرى إذا كان باقي النص يتوقع أو يعتمد على الإجراء الذي فشل بالفعل. والثاني هو أنه إذا احتاج برنامج نصي أو عملية أخرى إلى التحقق من نجاح أو فشل هذا البرنامج النصي ، فستحصل على قراءة خاطئة.
الخيار مجموعة ه
يؤدي خيار set -e
(exit) إلى إنهاء البرنامج النصي إذا كانت أي من العمليات التي يستدعيها تولد رمز إرجاع غير صفري. أي شيء غير صفري يعتبر فاشلاً.
بإضافة الخيار set -e
إلى بداية البرنامج النصي ، يمكننا تغيير سلوكه. هذا هو "script-3.sh."
#! / بن / باش مجموعة ه صدى هذا سيحدث أولاً ls اسم ملف وهمي صدى هذا سيحدث ثانيا
إذا قمنا بتشغيل هذا البرنامج النصي ، فسنرى تأثير set -e
.
./script-3.sh
صدى $؟
تم إيقاف البرنامج النصي وأصبح رمز الإرجاع المرسل إلى shell قيمة غير صفرية.
التعامل مع الأعطال في الأنابيب
تضيف الأنابيب مزيدًا من التعقيد إلى المشكلة. رمز الإرجاع الذي يخرج من تسلسل الأوامر بالأنابيب هو رمز الإرجاع من الأمر الأخير في السلسلة. إذا كان هناك فشل في أمر في منتصف السلسلة ، فنعود إلى المربع الأول. يتم فقد رمز الإرجاع هذا ، وسيستمر البرنامج النصي في المعالجة.
يمكننا أن نرى تأثيرات أوامر الأنابيب برموز الإرجاع المختلفة باستخدام الصدف true
false
المدمج. لا يقوم هذان الأمران بأكثر من إنشاء رمز إرجاع بقيمة صفر أو واحد ، على التوالي.
حقيقي
صدى $؟
خاطئة
صدى $؟
إذا قمنا بتوجيه false
إلى true
- مع تمثيل false
لعملية فاشلة - فإننا نحصل على كود إرجاع true
وهو صفر.
خطأ | حقيقي
صدى $؟
يحتوي Bash على متغير مصفوفة يسمى PIPESTATUS
، وهذا يلتقط جميع رموز الإرجاع من كل برنامج في سلسلة الأنابيب.
خطأ | صحيح | خطأ | حقيقي
صدى "$ {PIPESTATUS [0]} $ {PIPESTATUS [1]} $ {PIPESTATUS [2]} $ {PIPESTATUS [3]}"
PIPESTATUS
فقط بأكواد الإرجاع حتى يتم تشغيل البرنامج التالي ، ومحاولة تحديد رمز الإرجاع الذي يتناسب مع البرنامج الذي يمكن أن يصبح فوضويًا بسرعة كبيرة.
هنا يأتي دور set -o
(options) و pipefail
. هذا هو “script-4.sh.” سيحاول هذا توجيه محتويات ملف غير موجود إلى wc
.
#! / بن / باش مجموعة ه صدى هذا سيحدث أولاً cat script-99.sh | مرحاض -l صدى هذا سيحدث ثانيا
هذا فشل ، كما كنا نتوقع.
./script-4.sh
صدى $؟
الصفر الأول هو الناتج من wc
، مما يخبرنا أنه لم يقرأ أي أسطر للملف المفقود. الصفر الثاني هو رمز الإرجاع من أمر echo
الثاني.
سنضيف في ملف -o pipefail
، ونحفظه كـ "script-5.sh" ، ونجعله قابلاً للتنفيذ.
#! / بن / باش مجموعة -Eo pipefail صدى هذا سيحدث أولاً cat script-99.sh | مرحاض -l صدى هذا سيحدث ثانيا
لنقم بتشغيل ذلك والتحقق من رمز الإرجاع.
./script-5.sh
صدى $؟
يتوقف البرنامج النصي ولا يتم تنفيذ أمر echo
الثاني. رمز الإرجاع المرسل إلى الغلاف هو واحد ، مما يشير بشكل صحيح إلى الفشل.
ذات صلة: كيفية استخدام Echo Command على Linux
اصطياد المتغيرات غير المهيأة
قد يكون من الصعب تحديد المتغيرات غير المهيأة في نص برمجي حقيقي. إذا حاولنا echo
قيمة متغير غير مهيأ ، فإن echo
يطبع ببساطة سطرًا فارغًا. لا ترفع رسالة خطأ. سيستمر تنفيذ بقية البرنامج النصي.
هذا هو script-6.sh.
#! / بن / باش مجموعة -Eo pipefail صدى "notset $" صدى "أمر صدى آخر"
سنقوم بتشغيله ومراقبة سلوكه.
./script-6.sh
صدى $؟
يتخطى البرنامج النصي المتغير غير المهيأ ، ويستمر في التنفيذ. كود الإرجاع هو صفر. قد تكون محاولة العثور على خطأ مثل هذا في نص طويل ومعقد جدًا أمرًا صعبًا للغاية.
يمكننا اعتراض هذا النوع من الأخطاء باستخدام خيار set -u
(unset). سنضيف ذلك إلى مجموعتنا المتزايدة من خيارات المجموعة في الجزء العلوي من البرنامج النصي ، ونحفظه باسم "script-7.sh" ، ونجعله قابلاً للتنفيذ.
#! / بن / باش مجموعة -eou pipefail صدى "notset $" صدى "أمر صدى آخر"
لنقم بتشغيل البرنامج النصي:
./script-7.sh
صدى $؟
يتم اكتشاف المتغير غير المهيأ ، ويتوقف البرنامج النصي ، ويتم تعيين رمز الإرجاع على واحد.
يعد الخيار -u
(unset) ذكيًا بدرجة كافية بحيث لا يتم تشغيله من خلال المواقف التي يمكنك فيها التفاعل بشكل شرعي مع متغير غير مهيأ.
في “script-8.sh” ، يتحقق البرنامج النصي مما إذا كان المتغير New_Var
قد تمت تهيئته أم لا. لا تريد أن يتوقف النص عند هذا الحد ، ففي نص برمجي حقيقي ، ستجري مزيدًا من المعالجة والتعامل مع الموقف بنفسك.
لاحظ أننا أضفنا الخيار -u
كخيار ثانٍ في بيان المجموعة. يجب أن يأتي الخيار -o pipefail
أخيرًا.
#! / بن / باش مجموعة -euo pipefail إذا [-z "$ {New_Var: -}"]؛ ومن بعد صدى "New_Var ليس له قيمة مخصصة له." فاي
في “script-9.sh” ، يتم اختبار المتغير غير المهيأ وإذا كان غير مهيأ ، يتم تقديم قيمة افتراضية بدلاً من ذلك.
#! / بن / باش مجموعة -euo pipefail default_value = 484 القيمة = $ {New_Var: - $ default_value} صدى "New_Var = $ Value"
يُسمح للنصوص بالمرور حتى اكتمالها.
./script-8.sh
./script-9.sh
مختومة بالفأس
خيار آخر مفيد للاستخدام هو خيار set -x
(تنفيذ وطباعة). عندما تكتب نصوصًا ، يمكن أن يكون هذا منقذًا. يقوم بطباعة الأوامر ومعلماتها أثناء تنفيذها.
يمنحك شكلًا سريعًا "تقريبيًا وجاهزًا" لتتبع التنفيذ. يصبح عزل العيوب المنطقية واكتشاف الأخطاء أسهل بكثير.
سنضيف الخيار set -x إلى "script-8.sh" ، ونحفظه باسم "script-10.sh" ، ونجعله قابلاً للتنفيذ.
#! / بن / باش مجموعة -euxo pipefail إذا [-z "$ {New_Var: -}"]؛ ومن بعد صدى "New_Var ليس له قيمة مخصصة له." فاي
قم بتشغيله لرؤية خطوط التتبع.
./script-10.sh
من السهل اكتشاف الأخطاء في هذه الأمثلة التافهة. عندما تبدأ في كتابة المزيد من البرامج النصية المتضمنة ، ستثبت هذه الخيارات قيمتها.