كيفية استخدام getopts لتحليل خيارات Linux Shell Script

نشرت: 2022-06-25
شاشة كمبيوتر محمول تعرض نصًا طرفيًا.
fatmawati achmad zaenuri / Shutterstock.com

هل ترغب في أن تتعامل البرامج النصية لـ Linux shell مع خيارات سطر الأوامر والوسيطات بشكل أكثر رشاقة؟ يتيح لك برنامج Bash getopts المدمج إمكانية تحليل خيارات سطر الأوامر ببراعة — وهو سهل أيضًا. نوضح لك كيف.

نقدم لكم getopts المدمج

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

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

كيفية استخدام الأمر ls لسرد الملفات والدلائل على نظام Linux
ذات صلة كيفية استخدام الأمر ls لسرد الملفات والدلائل على Linux

يحتوي الأمر ls على أكثر من 50 خيارًا ، تتعلق بشكل أساسي بتنسيق مخرجاته. يقوم الخيار -X (فرز حسب الامتداد) بفرز الإخراج أبجديًا حسب امتداد الملف. يسرد الخيار -U (غير الفرز) حسب ترتيب الدليل.

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

تصبح الأمور أكثر تعقيدًا إذا كانت بعض خياراتك تأخذ وسيطة ، تُعرف باسم وسيطة الخيار ، على سبيل المثال ، يتوقع الخيار ls -w (العرض) أن يتبعه رقم يمثل أقصى عرض لعرض الناتج. وبالطبع ، قد تقوم بتمرير معلمات أخرى إلى البرنامج النصي الخاص بك والتي هي مجرد قيم بيانات ، وليست خيارات على الإطلاق.

لحسن الحظ ، يتعامل getopts مع هذا التعقيد نيابة عنك. ولأنه مدمج ، فهو متاح على جميع الأنظمة التي تحتوي على غلاف Bash ، لذلك لا يوجد شيء لتثبيته.

ملاحظة: getopts Not getopt

هناك أداة أقدم تسمى getopt . هذا برنامج فائدة صغير ، وليس برنامج مدمج. هناك العديد من الإصدارات المختلفة من getopt مختلفة ، في حين أن getops المدمج يتبع إرشادات POSIX.

 اكتب getopts
 اكتب getopt 

باستخدام الأمر type لمعرفة الفرق بين getop و getops

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

المفاضلة هي getopts لا تتعامل مع أسماء الخيارات ذات الشُّرط الطويلة والتنسيقات الطويلة. لذا يمكنك استخدام خيارات بتنسيق مثل -w ولكن ليس " ---wide-format ." من ناحية أخرى ، إذا كان لديك برنامج نصي يقبل الخيارات -a و -b و -c ، فإن getopts تتيح لك دمجها مثل -abc أو -bca أو -bac وما إلى ذلك.

نحن نناقش getopts في هذه المقالة ، لذا تأكد من إضافة الحرف "s" الأخير إلى اسم الأمر.

ذات صلة: كيفية الهروب من المسافات في مسارات الملفات على سطر أوامر Windows

خلاصة سريعة: معالجة قيم المعلمات

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

 #! / بن / باش

# احصل على المتغيرات واحدة تلو الأخرى
صدى "المتغير الأول: 1 دولار" 
صدى "المتغير الثاني: 2 دولار" 
صدى "المتغير الثالث: 3 دولارات"

# حلقة من خلال المتغيرات
لـ var في " $ @" do
صدى "$ var" 
فعله

يتم الوصول إلى المعلمات داخل البرنامج النصي كمتغيرات $1 أو $2 أو $3 .

انسخ هذا النص في محرر واحفظه كملف يسمى "variables.sh". سنحتاج إلى جعله قابلاً للتنفيذ باستخدام الأمر chmod . ستحتاج إلى القيام بهذه الخطوة لجميع النصوص التي نناقشها. فقط استبدل اسم ملف البرنامج النصي المناسب في كل مرة.

 chmod + x variables.sh 

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

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

 ./variables.sh 

تشغيل برنامج نصي بدون معلمات

لم نمرر أي معلمات لذا لا يحتوي النص البرمجي على قيم للإبلاغ عنها. دعنا نقدم بعض المعلمات هذه المرة.

 ./variables.sh كيفية المهوس 

تشغيل نص مكون من ثلاث كلمات كمعلماته

كما هو متوقع ، تم تعيين المتغيرات $1 و $2 و $3 على قيم المعلمات ونراها مطبوعة.

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

إذا قدمنا ​​معاملًا رابعًا ، فلن يتم تعيينه إلى متغير ، لكن الحلقة لا تزال تتعامل معه.

 ./variables.sh كيفية تطوير موقع الويب 

تمرير أربعة معلمات إلى برنامج نصي يمكنه التعامل مع ثلاثة فقط

إذا وضعنا علامات اقتباس حول كلمتين ، فسيتم التعامل معها كمعامل واحد.

 ./variables.sh كيفية "المهوس" 

نقلا عن اثنين من معلمات سطر الأوامر لمعاملتهم كمعامل واحد

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

لكن دعونا لا نركض قبل أن نتمكن من المشي. لنلقِ نظرة على أبسط حالة للتعامل مع خيارات سطر الأوامر.

خيارات المناولة

نستخدم getopts في حلقة while . يعمل كل تكرار للحلقة على خيار واحد تم تمريره إلى البرنامج النصي. في كل حالة ، يتم تعيين المتغير OPTION على الخيار المحدد بواسطة getopts .

مع كل تكرار للحلقة ، ينتقل getopts إلى الخيار التالي. عندما لا يكون هناك المزيد من الخيارات ، ترجع getopts false وتخرج حلقة while .

كيفية استخدام بيانات الحالة في نصوص Bash
ذات صلة كيفية استخدام بيانات الحالة في نصوص باش

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

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

انسخ هذا النص في محرر واحفظه كبرنامج نصي يسمى "options.sh" ، واجعله قابلاً للتنفيذ.

 #! / بن / باش

بينما خيار getopts 'abc' ؛ فعل
  الحالة "$ OPTION" في 
    أ) 
      صدى "الخيار مستخدم" ؛؛

    ب)
      صدى "الخيار ب المستخدم"
      ؛؛

    ج)
      صدى "الخيار ج المستخدم"
      ؛؛

    ؟) 
      صدى "Usage: $ (basename $ 0) [-a] [-b] [-c]"
      خروج 1
      ؛؛
  esac
فعله

هذا هو الخط الذي يحدد حلقة while.

 بينما خيار getopts 'abc' ؛ فعل

يتبع الأمر getopts سلسلة الخيارات . هذا يسرد الحروف التي سنستخدمها كخيارات. يمكن استخدام الأحرف في هذه القائمة فقط كخيارات. لذلك في هذه الحالة ، سيكون -d غير صالح. هذا من شأنه أن يقع في شرك ?) جملة لأن getopts تُرجع علامة استفهام " ? "لخيار غير محدد. إذا حدث ذلك ، تتم طباعة الاستخدام الصحيح في نافذة الجهاز:

 صدى "Usage: $ (basename $ 0) [-a] [-b] [-c]"

حسب الاصطلاح ، فإن التفاف خيار بين قوسين " [] " في هذا النوع من رسائل الاستخدام الصحيحة يعني أن الخيار اختياري. يزيل الأمر basename أي مسارات دليل من اسم الملف. اسم ملف البرنامج النصي محتجز في $0 في نصوص Bash النصية.

دعنا نستخدم هذا البرنامج النصي مع مجموعات سطر أوامر مختلفة.

 ./options.sh -a
 ./options.sh -a -b -c
 ./options.sh -ab -c
 ./options.sh -cab 

اختبار برنامج نصي يمكنه قبول خيارات سطر أوامر نوع التبديل

كما نرى ، يتم تحليل جميع مجموعات خيارات الاختبار لدينا ومعالجتها بشكل صحيح. ماذا لو جربنا خيارًا غير موجود؟

 ./options.sh -d 

خيار غير معروف تم الإبلاغ عنه بواسطة shell والبرنامج النصي

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

يعد إيقاف تشغيل رسائل خطأ shell أمرًا سهلاً للغاية. كل ما نحتاج إلى القيام به هو وضع علامة النقطتين " : " كأول حرف في سلسلة الخيارات.

إما أن تقوم بتحرير ملف "options.sh" وأضف نقطتين كحرف أول من سلسلة الخيارات ، أو احفظ هذا البرنامج النصي باسم "options2.sh" ، واجعله قابلاً للتنفيذ.

 #! / بن / باش

بينما getopts ': abc' OPTION ؛ فعل
  الحالة "$ OPTION" في 
    أ) 
      صدى "خيار مستعمل" 
      ؛؛

    ب)
      صدى "الخيار ب المستخدم"
      ؛؛

    ج)
      صدى "الخيار ج المستخدم"
      ؛؛

    ؟) 
      صدى "Usage: $ (basename $ 0) [-a] [-b] [-c]"
      خروج 1
      ؛؛
  esac
فعله

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

 ./options2.sh.sh -d 

خيار غير معروف يتم الإبلاغ عنه بواسطة البرنامج النصي وحده

استخدام getopts مع وسيطات الخيار

لإخبار getopts أن الخيار سيتبعه وسيطة ، ضع علامة النقطتين " : " مباشرةً خلف حرف الخيار في سلسلة الخيارات.

إذا اتبعنا "b" و "c" في سلسلة الخيارات مع النقطتين ، getopt وسيطات لهذه الخيارات. انسخ هذا النص في المحرر الخاص بك واحفظه باسم "arguments.sh" واجعله قابلاً للتنفيذ.

تذكر أن النقطتين الأولى في سلسلة الخيارات تُستخدم لمنع رسائل خطأ الصدفة - ولا علاقة لها بمعالجة الوسيطة.

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

 #! / بن / باش

بينما getopts ': ab: c:' OPTION ؛ فعل

  الحالة "$ OPTION" في
    أ)
      صدى "خيار مستعمل"
      ؛؛

    ب)
      argB = "$ OPTARG"
      صدى "الخيار ب المستخدم مع: $ argB"
      ؛؛

    ج)
      argC = "$ OPTARG"
      صدى "الخيار c يُستخدم مع: $ argC"
      ؛؛

    ؟)
      صدى "Usage: $ (basename $ 0) [-a] [-bإلى] [-c وسيطة]"
      خروج 1
      ؛؛
  esac

فعله

دعونا نجري ذلك ونرى كيف يعمل.

 ./arguments.sh -a -b "كيفية المهوس" -c reviewgeek
 ./arguments.sh -c reviewgeek -a 

اختبار برنامج نصي يمكنه التعامل مع وسيطات الخيارات

لذا يمكننا الآن التعامل مع الخيارات مع أو بدون وسيطات ، بغض النظر عن الترتيب الذي يتم تقديمه به في سطر الأوامر.

لكن ماذا عن البارامترات العادية؟ قلنا سابقًا أننا علمنا أنه يتعين علينا وضع هؤلاء في سطر الأوامر بعد أي خيارات. دعونا نرى ماذا سيحدث إذا فعلنا ذلك.

خيارات المزج والمعلمات

سنقوم بتغيير البرنامج النصي السابق ليشمل سطرًا إضافيًا. عندما تنتهي حلقة while loop ويتم التعامل مع جميع الخيارات ، سنحاول الوصول إلى المعلمات العادية. سنطبع القيمة $1 .

احفظ هذا البرنامج النصي باسم "arguments2.sh" ، واجعله قابلاً للتنفيذ.

 #! / بن / باش

بينما getopts ': ab: c:' OPTION ؛ فعل

  الحالة "$ OPTION" في
    أ)
      صدى "خيار مستعمل"
      ؛؛

    ب)
      argB = "$ OPTARG"
      صدى "الخيار ب المستخدم مع: $ argB"
      ؛؛

    ج)
      argC = "$ OPTARG"
      صدى "الخيار c يُستخدم مع: $ argC"
      ؛؛

    ؟)
      صدى "Usage: $ (basename $ 0) [-a] [-bإلى] [-c وسيطة]"
      خروج 1
      ؛؛
  esac

فعله

صدى "المتغير هو: $ 1"

سنحاول الآن مجموعة قليلة من الخيارات والمعلمات.

 ./arguments2.sh ديف
 ./arguments2.sh -a ديف
 ./arguments2.sh -a -c how-to-geek ديف 

فشل الوصول إلى المعلمات القياسية في البرنامج النصي الذي يقبل وسيطات الخيار

حتى الآن يمكننا أن نرى المشكلة. بمجرد استخدام أي خيارات ، تمتلئ المتغيرات $1 فصاعدًا بأعلام الخيارات ومعاملاتها. في المثال الأخير ، سيحتفظ $4 بقيمة المعلمة "dave" ، ولكن كيف يمكنك الوصول إلى ذلك في البرنامج النصي الخاص بك إذا كنت لا تعرف عدد الخيارات والوسيطات التي سيتم استخدامها؟

الإجابة هي استخدام OPTIND والأمر shift .

يتجاهل الأمر shift المعلمة الأولى - بغض النظر عن النوع - من قائمة المعلمات. المعلمات الأخرى "shuffle down" ، لذا فإن المعلمة 2 تصبح المعلمة 1 ، المعلمة 3 تصبح المعلمة 2 ، وهكذا. وهكذا يصبح $ $2 $1 ، $3 $2 أمريكية ، وهكذا.

إذا قمت بتوفير shift برقم ، فسيتم إزالة العديد من المعلمات من القائمة.

يحسب OPTIND الخيارات والوسيطات كما تم العثور عليها ومعالجتها. بمجرد معالجة جميع الخيارات OPTIND ، سيكون OPTIND أعلى من عدد الخيارات. لذلك إذا استخدمنا shift لتقطيع معلمات (OPTIND-1) من قائمة المعلمات ، فسنبقى مع المعلمات العادية في $1 فصاعدًا.

هذا بالضبط ما يفعله هذا البرنامج النصي. احفظ هذا البرنامج النصي باسم "arguments3.sh" واجعله قابلاً للتنفيذ.

 #! / بن / باش

بينما getopts ': ab: c:' OPTION ؛ فعل
  الحالة "$ OPTION" في
    أ)
      صدى "خيار مستعمل"
      ؛؛

    ب)
      argB = "$ OPTARG"
      صدى "الخيار ب المستخدم مع: $ argB"
      ؛؛

    ج)
      argC = "$ OPTARG"
      صدى "الخيار c يُستخدم مع: $ argC"
      ؛؛

    ؟)
      صدى "Usage: $ (basename $ 0) [-a] [-bإلى] [-c وسيطة]"
      خروج 1
      ؛؛
  esac
فعله

صدى "قبل - المتغير الأول هو: $ 1"
تحول "$ (($ OPTIND -1))"
صدى "بعد - المتغير الأول هو: $ 1"
صدى "بقية الحجج (المعاملات)"

لـ x في "$ @"
فعل
  صدى $ x
فعله

سنقوم بتشغيل هذا بمزيج من الخيارات والوسيطات والمعلمات.

 ./arguments3.sh -a -c How-to-Geek "ديف دي" dozy beaky mick tich 

الوصول الصحيح إلى المعلمات القياسية في برنامج نصي يقبل وسيطات الخيار

يمكننا أن نرى أنه قبل أن نطلق على shift ، كان $1 يحمل "-a" ، ولكن بعد الأمر shift ، يحمل $1 معلمة non-option ، بدون وسيطة. يمكننا إجراء حلقة عبر جميع المعلمات بنفس السهولة التي يمكننا بها في برنامج نصي بدون تحليل خيار.

من الجيد دائمًا أن يكون لديك خيارات

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