ארגומנטים של שורת הפקודה ב- Python

סקירה כללית

מכיוון ש-Python היא שפת תכנות פופולרית מאוד, כמו גם בעלת תמיכה ברוב מערכות ההפעלה וספריות רבות המקלות על עיבוד טיעונים בשורת הפקודה - היא הפכה בשימוש נרחב ליצירת כלי שורת פקודה למטרות רבות. כלים אלה יכולים לנוע בין אפליקציות CLI פשוטות לאלו מורכבות יותר, כמו AWS' awscli כלי.

כלים מורכבים כמו זה נשלטים בדרך כלל על ידי המשתמש באמצעות טיעוני שורת פקודה, המאפשר למשתמש להשתמש בפקודות ספציפיות, להגדיר אפשרויות ועוד. לדוגמה, אפשרויות אלה יכולות לומר לכלי להוציא מידע נוסף, לקרוא נתונים ממקור מסוים או לשלוח פלט למיקום מסוים.

באופן כללי, ארגומנטים מועברים לכלי CLI בצורה שונה, בהתאם למערכת ההפעלה שלך:

  • דמוי יוניקס: - ואחריו מכתב, כמו -h, או -- ואחריו מילה, כמו --help
  • Windows: / ואחריו אות או מילה כמו /help

גישות שונות אלו קיימות מסיבות היסטוריות. תוכניות רבות במערכות דמויות Unix תומכות הן בסימון המקף היחיד והן כפול. סימון המקף הבודד משמש בעיקר עם אפשרויות של אותיות בודדות, בעוד שמקפים כפולים מציגים רשימת אפשרויות קריאה יותר, וזה שימושי במיוחד עבור אפשרויות מורכבות שצריכות להיות מפורשות יותר.

הערות: במאמר זה נתמקד אך ורק בפורמט דמוי יוניקס של - ו --.

זכור שגם השם וגם המשמעות של טיעון הם ספציפיים לתוכנית - אין הגדרה כללית, מלבד כמה מוסכמות נפוצות כמו --help למידע נוסף על השימוש בכלי. כמפתחים של סקריפט Python, תחליט אילו ארגומנטים לספק למתקשר ומה הם עושים. זה דורש הערכה נכונה.

ככל שרשימת הארגומנטים הזמינים שלך תגדל, הקוד שלך יהפוך מורכב יותר בניסיון לנתח אותם במדויק. למרבה המזל, ב-Python יש מספר ספריות זמינות שיעזרו לך בכך. נסקור כמה מהפתרונות הנפוצים ביותר, שנעים בין "עשה זאת בעצמך" עם sys.argv, לגישת "עשה בשבילך" עם argparse.

טיפול בטיעונים של שורת הפקודה עם Python

Python 3+ והמערכת האקולוגית מסביב תומכים במספר דרכים שונות לטיפול בארגומנטים של שורת הפקודה. יש רב ספריות המאפשרות ניתוח של ארגומנטים בשורת הפקודה.

הדרך המובנית היא להשתמש ב- sys מודול. מבחינת שמות, והשימוש בו, הוא מתייחס ישירות לספריית C (libc).

הדרך השנייה היא ה getopt מודול, המטפל באפשרויות קצרות וארוכות כאחד, כולל הערכת ערכי הפרמטרים.

השמיים מודול argparse, אשר נגזר מה optparse מודול (זמין עד Python 2.7).

השמיים docopt מודול, כלומר זמין ב- GitHub, מאפשר גם את אותה פונקציונליות.

לאחרונה, absl הספרייה גם צוברת קיטור, כאמצעי להחליף optparse ו getopt().

לכל אחת מהדרכים הללו יש את היתרונות והחסרונות שלה, אז כדאי להעריך כל אחת מהן כדי לראות מה הכי מתאים לצרכים שלך.

מודול ה-sys

זהו מודול בסיסי שנשלח עם Python מהימים הראשונים. זה לוקח גישה דומה מאוד לספריית C באמצעות argc/argv כדי לגשת לטיעונים. ה מודול sys מיישם את הארגומנטים של שורת הפקודה במבנה רשימה פשוט בשם sys.argv.

כל רכיב רשימה מייצג ארגומנט בודד. הפריט הראשון ברשימה, sys.argv[0], הוא שמו של הסקריפט של Python. שאר מרכיבי הרשימה, 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))

שמור ותן שם לקובץ הזה 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 נועדה להביא ארגומנטים של שורת פקודה לייצור, עם ארגומנטים של שורת פקודה מבוזרת. כאשר מודול משתמש בדגלי שורת פקודה, ומיובא למודול אחר - המודול השני מייבאת גם את הדגלים, ויכול לעבד אותם על ידי העברתם למודול המיובא.

זה הופך ארגומנטים מורכבים של שורת פקודה המשותפים בין מודולים לקלים יותר ופחות מילוליים.

בנוסף, הספרייה מאפשרת לך להגדיר את ערכי ברירת המחדל, התיאורים וסוג הנתונים של הארגומנטים, כך שאין צורך בבדיקות והמרות נוספות.

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, עם שיטות עבודה מומלצות, סטנדרטים מקובלים בתעשייה ודף רמאות כלול. תפסיק לגוגל פקודות 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. טיעון זה מלווה בהודעת עזרה ברירת מחדל המתארת ​​את הטיעונים המקובלים.

הקוד שלהלן מציג את האתחול מנתח, ואת הפלט למטה שמציג את הקריאה הבסיסית, ואחריו הודעת העזרה. בניגוד לקריאות Python שבהן השתמשנו בדוגמאות הקודמות, זכור להשתמש ב- Python 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, כמו גם האפשרויות הקצרות והארוכות התקפות (הוצגו בקטע הקוד הקודם).

קריאת השיטה עצמה נשמרת בהצהרת try-catch כדי לכסות שגיאות במהלך ההערכה. מועלה חריג אם מתגלה טיעון שאינו חלק מהרשימה כפי שהוגדרה קודם לכן. הסקריפט של 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. כעת, אתה יכול בקלות להעריך את המשתנים האלה בקוד שלך. אנחנו יכולים להשתמש ב-a 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 כאופציה, שאינה חוקית.

סיכום

במאמר זה הראינו שיטות רבות ושונות לאחזור ארגומנטים של שורת הפקודה ב-Python, כולל שימוש sys, getopt, ו argparse. מודולים אלה משתנים בפונקציונליות, חלקם מספקים הרבה יותר מאחרים. sys גמיש לחלוטין, בעוד שניהם getoptו argparse דורש מבנה כלשהו. לעומת זאת, הם מכסים את רוב העבודה המורכבת ש sys משאיר בידיך. לאחר עיון בדוגמאות שסופקו, אתה אמור להיות מסוגל לקבוע איזה מודול מתאים ביותר לפרויקט שלך.

במאמר זה לא דיברנו על פתרונות אחרים כמו ה docopts מודול, רק הזכרנו את זה. מודול זה נוקט בגישה שונה לחלוטין, ויוסבר בפירוט באחד מהמאמרים הבאים.

הפניות

בול זמן:

עוד מ Stackabuse