النقاط الرئيسية
- تجعل عبارات Bash case النصوص أسهل للقراءة والصيانة مقارنة بعبارات if-then-else الطويلة.
- تطابق عبارة الحالة في Bash تعبيرًا مع الأنماط الموجودة في البنود وتنفذ العبارات وفقًا لذلك.
- يمكن استخدام أنماط متعددة في جملة واحدة، مما يجعل النص أكثر إيجازًا وفعالية. يمكن أيضًا استخدام الأرقام أو المتغيرات العددية في عبارات الحالة.
تعتبر عبارات Bash case قوية وسهلة الكتابة. عندما تعيد زيارة برنامج نصي قديم في Linux، فسوف تكون سعيدًا لأنك استخدمت عبارة case بدلاً من عبارة if-then-else الطويلة.
بيان القضية
تحتوي أغلب لغات البرمجة على نسختها الخاصة من عبارة switch أو case. وهي توجه تدفق تنفيذ البرنامج وفقًا لقيمة المتغير. عادةً، يوجد فرع تنفيذ محدد لكل من القيم المحتملة المتوقعة للمتغير وفرع شامل أو افتراضي لجميع القيم الأخرى.
الوظيفة المنطقية تشبه سلسلة طويلة من عبارات if-then مع عبارة else التي تلتقط كل شيء لم يتم التعامل معه مسبقًا بواسطة أحد if
تصريحات.
يحاول تنفيذ Bash لـ case مطابقة تعبير مع إحدى البنود. ويفعل ذلك من خلال النظر إلى كل بند بدوره، في محاولة للعثور على نمط مطابق. الأنماط في البنود عبارة عن سلاسل، ولكن – على عكس البديهة – هذا لا يعني أنه لا يمكننا استخدام القيم العددية كتعبير.
الحالة العامة
الشكل العام لبيان الحالة هو هذا:
case expression in pattern-1)
statement
;;
pattern-2)
statement
;;
.
.
.
pattern-N)
statement
;;
*)
statement
;;
esac
- يجب أن تبدأ عبارة الحالة بكلمة الحالة الأساسية وتنتهي بـ
esac
كلمة رئيسية. - يتم تقييم التعبير ومقارنته بالأنماط الموجودة في كل بند حتى يتم العثور على تطابق.
- يتم تنفيذ العبارة أو العبارات الموجودة في البند المطابق.
- “فاصلة منقوطة مزدوجة”
;;
” يتم استخدامه لإنهاء البند. - إذا تم مطابقة نمط وتم تنفيذ العبارات الموجودة في تلك الفقرة، فسيتم تجاهل جميع الأنماط الأخرى.
- لا يوجد حد لعدد البنود.
- علامة النجمة “
*
“يشير إلى النمط الافتراضي. إذا لم يتطابق تعبير مع أي من الأنماط الأخرى في بيان الحالة، فسيتم تنفيذ البند الافتراضي.
مثال بسيط
يخبرنا هذا النص بساعات العمل لمتجر وهمي. ويستخدم date
الأمر مع +"%a"
تنسيق السلسلة للحصول على اسم اليوم المختصر. يتم تخزين هذا في DayName
عامل.
#!/bin/bashDayName=$(date +"%a")
echo "Opening hours for $DayName"
case $DayName in
Mon)
echo "09:00 - 17:30"
;;
Tue)
echo "09:00 - 17:30"
;;
Wed)
echo "09:00 - 12:30"
;;
Thu)
echo "09:00 - 17:30"
;;
Fri)
echo "09:00 - 16:00"
;;
Sat)
echo "09:30 - 16:00"
;;
Sun)
echo "Closed all day"
;;
*)
;;
esac
انسخ هذا النص إلى محرر واحفظه كملف يسمى “open.sh”.
سنحتاج إلى استخدام الأمر chmod لجعله قابلاً للتنفيذ. ستحتاج إلى القيام بذلك لجميع البرامج النصية التي تنشئها أثناء عملك على هذه المقالة.
chmod +x open.sh
يمكننا الآن تشغيل البرنامج النصي الخاص بنا.
./open.sh
يصادف أن اليوم الذي تم التقاط لقطة الشاشة فيه هو يوم جمعة. وهذا يعني أن متغير DayName يحمل السلسلة “Fri”. وهذا يتطابق مع نمط “Fri” في البند “Fri)”.
لاحظ أن الأنماط في البنود لا تحتاج إلى وضعها بين علامتي اقتباس مزدوجتين، ولكن هذا لا يسبب أي ضرر إذا كانت كذلك. ومع ذلك، يجب عليك استخدام علامتي اقتباس مزدوجتين إذا كان النمط يحتوي على مسافات.
لقد تم ترك البند الافتراضي فارغًا. سيتم تجاهل أي شيء لا يتطابق مع أحد البنود السابقة.
هذا النص يعمل وهو سهل القراءة، لكنه طويل ومكرر. يمكننا اختصار هذا النوع من عبارات الحالة بسهولة تامة.
استخدام أنماط متعددة في جملة واحدة
من الميزات الرائعة لعبارات الحالة أنه يمكنك استخدام أنماط متعددة في كل جملة. إذا تطابق التعبير مع أي من هذه الأنماط، فسيتم تنفيذ العبارات في تلك الجملة.
إليك نصًا يخبرك بعدد أيام الشهر. لا يمكن أن تكون هناك سوى ثلاث إجابات: 30 يومًا، أو 31 يومًا، أو 28 أو 29 يومًا لشهر فبراير. لذا، على الرغم من وجود 12 شهرًا، فنحن نحتاج إلى ثلاث فقرات فقط.
في هذا البرنامج النصي، يُطلب من المستخدم إدخال اسم الشهر. ولجعل مطابقة النمط غير حساسة لحالة الأحرف، نستخدم أمر shopt مع خيار “-s nocasematch”. ولن يهم إذا كان الإدخال يحتوي على أحرف كبيرة أو صغيرة أو مزيج من الاثنين.
#!/bin/bashshopt -s nocasematch
echo "Enter name of a month"
read month
case $month in
February)
echo "28/29 days in $month"
;;
April | June | September | November)
echo "30 days in $month"
;;
January | March | May | July | August | October | December)
echo "31 days in $month"
;;
*)
echo "Unknown month: $month"
;;
esac
يحصل شهر فبراير على بند خاص به، وتشترك جميع الأشهر الأخرى في بندتين وفقًا لما إذا كانت تحتوي على 30 أو 31 يومًا. تستخدم البنود متعددة الأنماط رمز الأنبوب “|” كفاصل. تلتقط حالة الأحرف الافتراضية الأشهر المكتوبة بشكل سيئ.
لقد قمنا بحفظ هذا في ملف يسمى “month.sh”، وجعلناه قابلاً للتنفيذ.
chmod +x month.sh
سوف نقوم بتشغيل البرنامج النصي عدة مرات ونظهر أنه لا يهم إذا استخدمنا أحرفًا كبيرة أو صغيرة.
./month.sh
نظرًا لأننا طلبنا من البرنامج النصي تجاهل الاختلافات بين الأحرف الكبيرة والصغيرة، فإن أي اسم شهر مكتوب بشكل صحيح يتم التعامل معه بواسطة إحدى الجمل الرئيسية الثلاث. يتم التعامل مع الأشهر المكتوبة بشكل خاطئ بواسطة الجملة الافتراضية.
استخدام الأرقام في عبارات الحالة
يمكننا أيضًا استخدام الأرقام أو المتغيرات العددية كتعبير. يطلب هذا البرنامج النصي من المستخدم إدخال رقم في النطاق 1..3. ولتوضيح أن الأنماط في كل جملة هي سلاسل، فقد تم إحاطتها بعلامات اقتباس مزدوجة. وعلى الرغم من ذلك، لا يزال البرنامج النصي يطابق إدخال المستخدم للجملة المناسبة.
#!/bin/bashecho "Enter 1, 2, or 3: "
read Number
case $Number in
"1")
echo "Clause 1 matched"
;;
"2")
echo "Clause 2 matched"
;;
"3")
echo "Clause 3 matched"
;;
*)
echo "Default clause matched"
;;
esac
./number.sh
استخدام عبارات الحالة في حلقات for
تحاول عبارة الحالة مطابقة نمط تعبير واحد. إذا كان لديك الكثير من التعبيرات التي يجب معالجتها، فيمكنك وضع عبارة الحالة داخل حلقة for.
يقوم هذا البرنامج النصي بتنفيذ الأمر ls للحصول على قائمة بالملفات. في حلقة for، يتم تطبيق التجميع للملفات — على غرار التعبيرات العادية ولكن بشكل مختلف — على كل ملف بدوره لاستخراج امتداد الملف. يتم تخزين هذا في متغير سلسلة الامتداد.
تستخدم عبارة الحالة متغير الامتداد باعتباره التعبير الذي تحاول مطابقته مع شرط ما.
#!/bin/bashfor File in $(ls)
do
Extension=${File
case "$Extension" in
sh)
echo " Shell script: $File"
;;
md)
echo " Markdown file: $File"
;;
png)
echo "PNG image file: $File"
;;
*)
echo "Unknown: $File"
;;
esac
done
احفظ هذا النص في ملف يسمى “filetype.sh”، واجعله قابلاً للتنفيذ، ثم قم بتشغيله باستخدام:
./filetype.sh
يعمل البرنامج النصي الخاص بنا لتحديد نوع الملف البسيط.
التعامل مع رموز الخروج باستخدام عبارات الحالة
سيرسل البرنامج الذي يتصرف بشكل جيد رمز خروج إلى shell عند إنهائه. يستخدم المخطط التقليدي قيمة رمز الخروج صفرًا للإشارة إلى تنفيذ خالٍ من المشكلات، وقيمًا تساوي واحدًا أو أكثر للإشارة إلى أنواع مختلفة من الأخطاء.
تستخدم العديد من البرامج فقط الصفر والواحد. إن تجميع كل شروط الخطأ في رمز خروج واحد يجعل تحديد المشكلات أكثر صعوبة، ولكن هذه ممارسة شائعة.
لقد قمنا بإنشاء برنامج صغير يسمى “go-geek” والذي يقوم بإرجاع رموز الخروج بشكل عشوائي تساوي صفرًا أو واحدًا. يقوم البرنامج النصي التالي باستدعاء go-geek. يقوم البرنامج النصي بالحصول على رمز الخروج باستخدام متغير shell $? ويستخدمه كتعبير لبيان الحالة.
سوف يقوم البرنامج النصي في العالم الحقيقي بإجراء المعالجة المناسبة وفقًا لنجاح أو فشل الأمر الذي أنشأ رمز الخروج.
#!/bin/bashgo-geek
case $? in
"0")
echo "Response was: Success"
echo "Do appropriate processing in here"
;;
"1")
echo "Response was: Error"
echo "Do appropriate error handling in here"
;;
*)
echo "Unrecognised response: $?"
;;
esac
احفظ هذا في نص برمجي يسمى “return-code.sh” واجعله قابلاً للتنفيذ. ستحتاج إلى استبدال أمر go-geek الخاص بنا بأمر آخر. يمكنك محاولة إدخال cd في دليل غير موجود للحصول على رمز خروج بقيمة 1، ثم تعديل النص البرمجي الخاص بك إلى cd في دليل يمكن الوصول إليه للحصول على رمز خروج بقيمة صفر.
يؤدي تشغيل البرنامج النصي عدة مرات إلى إظهار رموز الخروج المختلفة التي تم تحديدها بشكل صحيح بواسطة بيان الحالة.
./return-code.sh
تساعد القابلية للقراءة على سهولة الصيانة
إن العودة إلى نصوص Bash القديمة ومعرفة كيفية عملها، وخاصة إذا كتبها شخص آخر، أمر صعب. كما أن تعديل وظائف النصوص القديمة أصعب.
توفر لك عبارة الحالة منطقًا متفرعًا مع بناء جملة واضح وسهل. وهذا وضع مربح للجانبين.