نبذة
نظرًا لكون لغة Python لغة برمجة شائعة جدًا، فضلاً عن دعمها لمعظم أنظمة التشغيل والعديد من المكتبات التي تجعل معالجة وسيطات سطر الأوامر أمرًا سهلاً، فقد أصبحت تُستخدم على نطاق واسع لإنشاء أدوات سطر الأوامر للعديد من الأغراض. يمكن أن تتراوح هذه الأدوات من تطبيقات CLI البسيطة إلى التطبيقات الأكثر تعقيدًا، مثل AWS أوسكلي الأداة.
عادةً ما يتم التحكم في الأدوات المعقدة مثل هذه بواسطة المستخدم عبر وسائط سطر الأوامر، والذي يسمح للمستخدم باستخدام أوامر محددة، وتعيين الخيارات، والمزيد. على سبيل المثال، يمكن لهذه الخيارات أن تطلب من الأداة إخراج معلومات إضافية، أو قراءة البيانات من مصدر محدد، أو إرسال المخرجات إلى موقع معين.
بشكل عام، يتم تمرير الوسائط إلى أدوات واجهة سطر الأوامر (CLI) بشكل مختلف، اعتمادًا على نظام التشغيل الخاص بك:
- يونكس مثل:
-
يليه حرف مثل-h
الطرق أو--
تليها كلمة مثل--help
- نوافذ:
/
يليه إما حرف، أو كلمة، مثل/help
توجد هذه الأساليب المختلفة لأسباب تاريخية. تدعم العديد من البرامج الموجودة على الأنظمة المشابهة لنظام Unix كلاً من تدوين الشرطة المفردة والمزدوجة. يتم استخدام تدوين الشرطة المفردة في الغالب مع خيارات الحرف المفرد، بينما تقدم الشرطات المزدوجة قائمة خيارات أكثر قابلية للقراءة، وهو أمر مفيد بشكل خاص للخيارات المعقدة التي تحتاج إلى أن تكون أكثر وضوحًا.
ملاحظات: في هذه المقالة سنركز فقط على التنسيق المشابه لنظام Unix -
و --
.
ضع في اعتبارك أن اسم ومعنى الوسيطة خاصان بالبرنامج - لا يوجد تعريف عام، بخلاف بعض الاتفاقيات الشائعة مثل --help
لمزيد من المعلومات حول استخدام الأداة. باعتبارك مطور برنامج Python النصي، ستقرر أي الحجج ستقدمها للمتصل وما سيفعله. وهذا يتطلب التقييم السليم.
مع نمو قائمة الوسائط المتاحة لديك، ستصبح التعليمات البرمجية الخاصة بك أكثر تعقيدًا في محاولة تحليلها بدقة. لحسن الحظ، يوجد في بايثون عدد من المكتبات المتاحة لمساعدتك في ذلك. سنغطي بعضًا من الحلول الأكثر شيوعًا، والتي تتراوح بين "افعل ذلك بنفسك" باستخدام sys.argv
، إلى نهج "تم إنجازه من أجلك" مع argparse
.
التعامل مع وسيطات سطر الأوامر مع بايثون
يدعم إصدار Python 3+ والنظام البيئي المحيط به عددًا من الطرق المختلفة للتعامل مع وسيطات سطر الأوامر. هناك كثير المكتبات التي تسهل تحليل وسيطات سطر الأوامر.
الطريقة المضمنة هي استخدام sys
وحدة. من حيث الأسماء واستخدامها فهي تتعلق مباشرة بمكتبة C (libc
).
الطريقة الثانية هي getopt
الوحدة، التي تتعامل مع الخيارات القصيرة والطويلة، بما في ذلك تقييم قيم المعلمات.
• وحدة argparse، وهو مشتق من optparse
الوحدة (متوفرة حتى Python 2.7).
• docopt
الوحدة النمطية، وهي متاح على جيثب، كما يسمح بنفس الوظيفة.
في الآونة الأخيرة، absl
اكتسبت المكتبة أيضًا قوة، كوسيلة للاستبدال optparse
و getopt()
.
كل من هذه الطرق لها إيجابياتها وسلبياتها، لذا من المفيد تقييم كل منها لمعرفة أيها يناسب احتياجاتك بشكل أفضل.
وحدة النظام
هذه وحدة أساسية تم شحنها مع بايثون منذ الأيام الأولى. يتطلب الأمر نهجًا مشابهًا جدًا لاستخدام مكتبة C argc
/argv
للوصول إلى الحجج. ال وحدة النظام ينفذ وسيطات سطر الأوامر في بنية قائمة بسيطة تسمى sys.argv
.
يمثل كل عنصر في القائمة وسيطة واحدة. العنصر الأول في القائمة،
sys.argv[0]
، هو اسم البرنامج النصي بايثون. باقي عناصر القائمةsys.argv[1]
إلىsys.argv[n]
، هي وسيطات سطر الأوامر من 2 إلى n.
كمحدد بين الوسائط، يتم استخدام مسافة. يجب أن تكون قيم الوسيطة التي تحتوي على مسافة محاطة بعلامات اقتباس حتى يتم تحليلها بشكل صحيح sys
.
أي ما يعادل argc
هو مجرد عدد العناصر في القائمة. للحصول على هذه القيمة، استخدم Python len()
المشغل أو العامل. سنعرض ذلك في مثال التعليمات البرمجية لاحقًا.
طباعة وسيطة CLI الأولى
في هذا المثال الأول، سيحدد البرنامج النصي الطريقة التي تم استدعاؤه بها. يتم الاحتفاظ بهذه المعلومات في وسيطة سطر الأوامر الأولى، المفهرسة بالرقم 0. يوضح الكود أدناه كيفية حصولك على اسم برنامج Python النصي الخاص بك:
import sys
print("The script has the name %s" % (sys.argv[0])
احفظ هذا الكود في ملف اسمه arguments-program-name.py
، ثم قم بتسميته كما هو موضح أدناه. الإخراج كما يلي ويحتوي على اسم الملف، بما في ذلك مساره الكامل:
$ python arguments-program-name.py
The script has the name arguments-program-name.py
$ python /home/user/arguments-program-name.py
The script has the name /home/user/arguments-program-name.py
كما ترون من الاستدعاء الثاني أعلاه، فإننا لا نحصل على اسم ملف Python فحسب، بل نحصل أيضًا على المسار الكامل المستخدم لاستدعائه.
حساب عدد الحجج
في هذا المثال الثاني، نقوم ببساطة بحساب عدد وسيطات سطر الأوامر باستخدام الملف المدمج len()
الأسلوب. sys.argv
هي القائمة التي يتعين علينا فحصها. في الكود أدناه، نحصل على عدد الوسائط ثم نطرح 1 لأن إحدى هذه الوسائط (أي الوسيطة الأولى) يتم تعيينها دائمًا كاسم للملف، وهو ما لا يكون مفيدًا لنا دائمًا. وبالتالي، فإن العدد الفعلي للوسائط التي مررها المستخدم هو len(sys.argv) - 1
:
import sys
arguments = len(sys.argv) - 1
print ("The script is called with %i arguments" % (arguments))
احفظ هذا الملف وقم بتسميته وسيطات-count.py. بعض الأمثلة على استدعاء هذا البرنامج النصي موضحة أدناه. يتضمن ذلك ثلاثة سيناريوهات مختلفة:
- مكالمة بدون أي وسيطات سطر أوامر أخرى
- دعوة ذات حجتين
- استدعاء يحتوي على وسيطتين، حيث تكون الوسيطة الثانية عبارة عن سلسلة نصية مقتبسة تحتوي على مسافة
$ python arguments-count.py
The script is called with 0 arguments
$ python arguments-count.py --help me
The script is called with 2 arguments
$ python arguments-count.py --option "long string"
The script is called with 2 arguments
التكرار من خلال الحجج
يقوم المثال الثالث بإخراج كل وسيطة تم إرسالها إلى برنامج Python النصي، باستثناء اسم البرنامج نفسه. لذلك، نقوم بالتكرار خلال وسيطات سطر الأوامر بدءًا من ثان عنصر القائمة. تذكر أن هذا هو الفهرس 1 نظرًا لأن القوائم تعتمد على 0 في Python:
import sys
arguments = len(sys.argv) - 1
position = 1
while (arguments >= position):
print ("Parameter %i: %s" % (position, sys.argv[position]))
position = position + 1
أدناه نسمي الكود الخاص بنا، والذي تم حفظه في الملفarguments-output.py. كما حدث مع مثالنا السابق، يوضح الناتج ثلاثة استدعاءات مختلفة:
- دعوة دون أي حجج
- دعوة ذات حجتين
- استدعاء ذو وسيطتين، حيث تكون الوسيطة الثانية عبارة عن سلسلة مقتبسة تحتوي على مسافة
$ python arguments-output.py
$ python arguments-output.py --help me
Parameter 1: --help
Parameter 2: me
$ python arguments-output.py --option "long string"
Parameter 1: --option
Parameter 2: long string
تذكر أن الهدف من عرض مثال السلسلة المقتبسة هو أن المعلمات عادة ما تكون محددة بمسافة، ما لم إنهم محاطون بالاقتباسات.
أعلام أبسيل (absl
)
تهدف مكتبة Abseil's Flags إلى جلب وسائط سطر الأوامر إلى الإنتاج، مع وسائط سطر الأوامر الموزعة. عندما تستخدم الوحدة إشارات سطر الأوامر، ويتم استيرادها إلى وحدة أخرى - الوحدة الأخرى تستورد الأعلام كذلكويمكن معالجتها عن طريق إعادة توجيهها إلى الوحدة المستوردة.
وهذا يجعل وسيطات سطر الأوامر المعقدة المشتركة بين الوحدات أسهل وأقل تفصيلاً.
بالإضافة إلى ذلك، تتيح لك المكتبة تحديد القيم الافتراضية للوسيطات وأوصافها ونوع بياناتها، لذلك لا يلزم إجراء عمليات فحص وتحويلات إضافية.
from absl import flags
import sys
flags.DEFINE_string('name', 'User', 'The name of the user.')
FLAGS = flags.FLAGS
FLAGS(sys.argv)
print(f"Hello {FLAGS.name}!")
أنواع البيانات المدعومة هي:
DEFINE_integer()
DEFINE_string()
DEFINE_bool()
DEFINE_enum()
DEFINE_list()
DEFINE_float()
إضافة إلى DEFINE_multi_integer()
, DEFINE_multi_string()
و DEFINE_multi_enum()
لإدخال الوسائط المتعددة. بالإضافة إلى ذلك، تشغيل --help
, --helpfull
إلخ. طباعة الأعلام الموجودة وأوصافها بتنسيقات مختلفة.
تحقق من دليلنا العملي العملي لتعلم Git ، مع أفضل الممارسات ، والمعايير المقبولة في الصناعة ، وورقة الغش المضمنة. توقف عن أوامر Googling Git وفي الواقع تعلم ذلك!
تتيح لك المكتبة أيضًا تحديد عمليات التحقق من الصحة - سواء من حيث النطاق، مثل القيم المستندة إلى الأعداد الصحيحة التي تحتوي على upper_bound
or lower_bound
هذا مقبول، ويتم تشغيل أساليب عشوائية للتحقق من القيم:
def validate_name(value):
return len(value) > 15
flags.register_validator('name',
validate_name,
message='Name is over 15 characters long.',
flag_values=FLAGS)
جمع هذه في مثال ملموس:
from absl import flags
import sys
flags.DEFINE_string('name', 'User', 'The name of the user.')
flags.DEFINE_integer('tasks', 0, 'The number of tasks a user has.', lower_bound=0)
FLAGS = flags.FLAGS
FLAGS(sys.argv)
print(f"{FLAGS.name} has {FLAGS.tasks} tasks to work on.")
$ python flags.py --name=John --tasks=5
John has 5 tasks to work on.
$ python flags.py --name=John --tasks=-1
Traceback (most recent call last):
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/absl/flags/_flag.py", line 180, in _parse
return self.parser.parse(argument)
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/absl/flags/_argument_parser.py", line 168, in parse
raise ValueError('%s is not %s' % (val, self.syntactic_help))
ValueError: -1 is not a non-negative integer
...
وحدة argparse
• وحدة argparse أصبح متاحًا منذ إصدار Python 3.2، وتحسينًا لـ optparse
الوحدة الموجودة حتى Python 2.7. تحتوي وثائق Python على وصف لواجهة برمجة التطبيقات (API) وبرنامج تعليمي يغطي جميع الطرق بالتفصيل.
توفر الوحدة واجهة سطر أوامر بمخرجات موحدة، في حين أن الحلين السابقين يتركان الكثير من العمل بين يديك. argparse
يسمح بالتحقق من الوسائط الثابتة والاختيارية، مع التحقق من الاسم إما بنمط قصير أو طويل. كوسيطة اختيارية افتراضية، فهي تتضمن -h
، إلى جانب نسخته الطويلة --help
. تكون هذه الوسيطة مصحوبة برسالة تعليمات افتراضية تصف الوسائط المقبولة.
يعرض الكود أدناه تهيئة المحلل اللغوي، ويوضح الإخراج أدناه المكالمة الأساسية، متبوعة برسالة المساعدة. على عكس استدعاءات بايثون التي استخدمناها في الأمثلة السابقة، ضع في اعتبارك استخدام بايثون 3 مع هذه الأمثلة:
import argparse
parser = argparse.ArgumentParser()
parser.parse_args()
$ python3 arguments-argparse-basic.py
$ python3 arguments-argparse-basic.py -h
usage: arguments-argparse-basic.py [-h]
optional arguments:
-h, --help show this help message and exit
$ python3 arguments-argparse-basic.py --verbose
usage: arguments-argparse-basic.py [-h]
arguments-argparse-basic.py: error: unrecognized arguments: --verbose
في الخطوة التالية، سنضيف وصفًا مخصصًا لرسالة المساعدة لمستخدمينا. تتيح تهيئة المحلل اللغوي بهذه الطريقة نصًا إضافيًا. يخزن الكود أدناه الوصف في ملف text
المتغير، والذي يُعطى صراحةً لـ argparse
الطبقة كما description
معامل. باستدعاء هذا الكود أدناه، يمكنك رؤية الشكل الناتج:
import argparse
text = 'This is a test program. It demonstrates how to use the argparse module with a program description.'
parser = argparse.ArgumentParser(description=text)
parser.parse_args()
$ python3 arguments-argparse-description.py --help
usage: arguments-argparse-description.py [-h]
This is a test program. It demonstrates how to use the argparse module with a
program description.
optional arguments:
-h, --help show this help message and exit
كخطوة أخيرة، سنضيف وسيطة اختيارية مسماة -V
، والتي تحتوي على وسيطة نمط طويل مقابلة مسماة --version
. للقيام بذلك نستخدم الطريقة add_argument()
التي نسميها بثلاث معلمات (يتم عرضها لـ --version
، فقط):
- اسم المعامل:
--version
- نص المساعدة للمعلمة:
help="show program version"
- الإجراء (بدون قيمة إضافية):
action="store_true"
يتم عرض الكود المصدري لذلك أدناه. قراءة الوسائط في المتغير المسمى args
يتم عبر parse_args()
طريقة من parser
هدف. لاحظ أنك ترسل كلا من النسخة القصيرة والطويلة في مكالمة واحدة. وأخيرا، عليك التحقق مما إذا كانت السمات args.V
or args.version
يتم ضبطها وإخراج رسالة الإصدار:
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("-V", "--version", help="show program version", action="store_true")
args = parser.parse_args()
if args.version:
print("This is myprogram version 0.1")
$ python3 arguments-argparse-optional.py -V
This is myprogram version 0.1
$ python3 arguments-argparse-optional.py --version
This is myprogram version 0.1
• --version
لا تتطلب الوسيطة إعطاء قيمة في سطر الأوامر. لهذا السبب قمنا بتعيين حجة العمل على "store_true"
. وفي حالات أخرى، قد تحتاج إلى قيمة إضافية معينة، على سبيل المثال، إذا حددت حجمًا أو ارتفاعًا أو عرضًا معينًا. ويظهر هذا في المثال التالي. كحالة افتراضية، يرجى ملاحظة أنه يتم تفسير جميع الوسائط كسلاسل:
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("--width", "-w", help="set output width")
args = parser.parse_args()
if args.width:
print("Set output width to %s" % args.width)
نعرض هنا ما يحدث عند إرسال قيم وسيطات مختلفة. يتضمن ذلك الإصدارين القصير والطويل، بالإضافة إلى رسالة المساعدة:
$ python3 arguments-argparse-optional2.py -w 10
Set output width to 10
$ python3 arguments-argparse-optional2.py --width 10
Set output width to 10
$ python3 arguments-argparse-optional2.py -h
usage: arguments-argparse-optional2.py [-h] [--width WIDTH]
optional arguments:
-h, --help show this help message and exit
--width WIDTH, -w WIDTH
set output width
وحدة getopt
كما لاحظتم من قبل، فإن sys
تقوم الوحدة النمطية بتقسيم سلسلة سطر الأوامر إلى جوانب فردية فقط. بايثون وحدة getopt يذهب أبعد قليلاً ويوسع فصل سلسلة الإدخال عن طريق التحقق من صحة المعلمة. على أساس getopt
C، فهي تتيح خيارات قصيرة وطويلة، بما في ذلك تعيين القيمة.
ومن الناحية العملية، فإنه يتطلب sys
وحدة لمعالجة بيانات الإدخال بشكل صحيح. للقيام بذلك، كل من sys
الوحدة النمطية و getopt
يجب تحميل الوحدة مسبقًا. بعد ذلك، من قائمة معلمات الإدخال، نقوم بإزالة عنصر القائمة الأول (انظر الكود أدناه)، وتخزين القائمة المتبقية من وسائط سطر الأوامر في المتغير المسمى argument_list
:
import getopt, sys
full_cmd_arguments = sys.argv
argument_list = full_cmd_arguments[1:]
print argument_list
الحجج في argument_list
يمكن الآن تحليلها باستخدام getopts()
طريقة. ولكن قبل أن نفعل ذلك، علينا أن نقول getopts()
حول المعلمات الصالحة. يتم تعريفها على النحو التالي:
short_options = "ho:v"
long_options = ["help", "output=", "verbose"]
وهذا يعني أن هذه الحجج هي التي نعتبرها صالحة، إلى جانب بعض المعلومات الإضافية:
------------------------------------------
long argument short argument with value
------------------------------------------
--help -h no
--output -o yes
--verbose -v no
------------------------------------------
ربما لاحظت أن ملف o
تم تنفيذ الخيار القصير بواسطة القولون، :
. هذا يروي getopt
أنه يجب تعيين قيمة لهذا الخيار.
يتيح لنا هذا الآن معالجة قائمة الوسائط. ال getopt()
تتطلب الطريقة تكوين ثلاث معلمات - قائمة الوسائط الفعلية من argv
، بالإضافة إلى الخيارين القصير والطويل الصالحين (الموضحين في مقتطف الشفرة السابق).
يتم الاحتفاظ باستدعاء الأسلوب نفسه في بيان محاولة الالتقاط لتغطية الأخطاء أثناء التقييم. يتم ظهور استثناء إذا تم اكتشاف وسيطة ليست جزءًا من القائمة كما تم تعريفها من قبل. سيقوم برنامج Python النصي بطباعة رسالة الخطأ على الشاشة، ويخرج برمز الخطأ 2:
try:
arguments, values = getopt.getopt(argument_list, short_options, long_options)
except getopt.error as err:
print (str(err))
sys.exit(2)
وأخيرًا، يتم تخزين الوسيطات ذات القيم المقابلة في المتغيرين المذكورين arguments
و values
. الآن، يمكنك بسهولة تقييم هذه المتغيرات في التعليمات البرمجية الخاصة بك. يمكننا استخدام أ for
-حلقة للتكرار من خلال قائمة الوسائط المعترف بها، إدخال واحد بعد الآخر.
for current_argument, current_value in arguments:
if current_argument in ("-v", "--verbose"):
print ("Enabling verbose mode")
elif current_argument in ("-h", "--help"):
print ("Displaying help")
elif current_argument in ("-o", "--output"):
print (("Enabling special output mode (%s)") % (current_value))
أدناه يمكنك رؤية الإخراج من تنفيذ هذا الرمز. سنوضح كيف يتفاعل البرنامج مع كل من وسيطات البرنامج الصالحة وغير الصالحة:
$ python arguments-getopt.py -h
Displaying help
$ python arguments-getopt.py --help
Displaying help
$ python arguments-getopt.py --output=green --help -v
Enabling special output mode (green)
Displaying help
Enabling verbose mode
$ python arguments-getopt.py -verbose
option -e not recognized
قد يبدو النداء الأخير لبرنامجنا مربكًا بعض الشيء في البداية. لفهم ذلك، عليك أن تعرف أنه يمكن استخدام خيارات الاختصار (التي تسمى أحيانًا الأعلام) مع شرطة واحدة. يتيح ذلك لأداتك قبول العديد من الخيارات بسهولة أكبر. على سبيل المثال، الدعوة python arguments-getopt.py -vh
هو نفس الدعوة python arguments-getopt.py -v -h
. لذلك في المكالمة الأخيرة أعلاه، getopt
اعتقدت الوحدة أن المستخدم كان يحاول المرور -e
كخيار، وهو غير صالح.
وفي الختام
لقد أظهرنا في هذه المقالة العديد من الطرق المختلفة لاسترداد وسيطات سطر الأوامر في بايثون، بما في ذلك استخدام sys
, getopt
و argparse
. تختلف هذه الوحدات في وظائفها، حيث يوفر بعضها أكثر بكثير من غيرها. sys
مرنة تماما، في حين أن كليهما getopt
و argparse
تتطلب بعض الهيكل. وفي المقابل، فإنها تغطي معظم الأعمال المعقدة التي sys
يترك الأمر لك. بعد العمل على الأمثلة المقدمة، يجب أن تكون قادرًا على تحديد الوحدة التي تناسب مشروعك بشكل أفضل.
في هذه المقالة لم نتحدث عن حلول أخرى مثل docopts
الوحدة النمطية، ذكرنا ذلك للتو. تتبع هذه الوحدة نهجًا مختلفًا تمامًا، وسيتم شرحها بالتفصيل في إحدى المقالات التالية.