0Pricing
DevOps Bootcamp · درس

تحليل الأعلام والوسائط باستخدام getopts

نفّذ واجهات سطر أوامر احترافية باستخدام getopts للخيارات القصيرة والوسائط المطلوبة ورسائل الاستخدام.

تحليل الأعلام والوسائط باستخدام getopts درس مجاني في DevOps Bootcamp على CoddyKit. هذا هو الدرس 3 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في DevOps Bootcamp، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة DevOps Bootcamp 4 دروس في المجموع.

سبب وجود getopts

يحتاج كل برنامج نصي واقعي في مرحلة ما إلى قبول خيارات مثل -v أو -o output.txt أو -n 5. وسرعان ما تصبح معالجة هذه الخيارات يدويًا باستخدام $1 و$2… هشة.

إن getopts هو الأمر المدمج المتوافق مع معيار POSIX، ويتولى معالجة الخيارات القصيرة (-a و-b) بشكل موثوق، بما في ذلك الخيارات التي تتطلب وسيطًا. وهو مدمج في كل shell متوافق مع POSIX، لذلك لا حاجة إلى أي تبعيات.

  • يتعامل مع الرايات المدمجة: -vn 5 = -v -n 5
  • يُبلغ عن الخيارات غير المعروفة بطريقة سلسة
  • يضبط المتغيرين المعياريين OPTIND وOPTARG تلقائيًا

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

بنية getopts

البنية الأساسية هي حلقة while تستدعي getopts في كل تكرار:

while getopts "optstring" varname; do
  case "$varname" in
    ...
  esac
done
  • optstring — سلسلة تسرد حروف الخيارات المقبولة. وتعني النقطتان بعد الحرف أن هذا الخيار يتطلب وسيطًا.
  • varname — يستقبل حرف الخيار الحالي في كل تكرار.
  • OPTARG — يُضبط تلقائيًا على قيمة الوسيط عندما تتبع النقطتان الحرف.
  • OPTIND — فهرس الوسيط التالي الذي ستتم معالجته؛ استخدم shift $((OPTIND - 1)) بعد الحلقة لإتاحة المعاملات الموضعية المتبقية.
#!/usr/bin/env bash
# Minimal skeleton — shows the loop structure
while getopts 'vn:' opt; do
  case "$opt" in
    v) echo "Verbose mode on" ;;
    n) echo "Count = $OPTARG" ;;
    ?) echo "Unknown option: -$OPTARG" >&2; exit 1 ;;
  esac
done

تعريف optstring

إن optstring إعلان موجز لعقد واجهة سطر الأوامر CLI الخاصة بكم. ويمثل كل حرف راية مقبولة.

  • 'abc' — يقبل -a و-b و-c (من دون وسائط)
  • 'a:bc' — يتطلب -a وسيطًا؛ أما -b و-c فلا يتطلبانه
  • ':abc' — يفعّل النقطتان في البداية وضع الأخطاء الصامت (يتولى برنامجكم معالجة الخيارات غير الصحيحة بدلًا من طباعة الصدفة رسالة)

يُفضَّل الوضع الصامت في البرامج النصية المخصصة للإنتاج لأنه يمنحكم تحكمًا كاملًا في رسائل الخطأ ورموز الخروج.

#!/usr/bin/env bash
# optstring ':o:vq'
# -o  requires an argument (output file)
# -v  verbose flag (no argument)
# -q  quiet flag  (no argument)
# Leading ':' = silent error mode

while getopts ':o:vq' opt; do
  case "$opt" in
    o) OUTPUT="$OPTARG" ;;
    v) VERBOSE=1 ;;
    q) QUIET=1 ;;
    :) echo "Error: -$OPTARG requires an argument" >&2; exit 1 ;;
    \?) echo "Error: unknown option -$OPTARG" >&2; exit 1 ;;
  esac
done
echo "OUTPUT=$OUTPUT  VERBOSE=$VERBOSE  QUIET=$QUIET"

OPTARG والوسائط المطلوبة

عندما يتبع حرف الراية نقطتان في optstring، يخزّن getopts قيمتها في OPTARG. ويمكن للمستخدم كتابة الوسيط مع مسافة أو من دونها:

  • -o report.txt
  • -oreport.txt

تتم معالجة الصيغتين بالطريقة نفسها. وهذه إحدى المزايا الأساسية مقارنةً بالمعالجة اليدوية باستخدام $1/shift.

في الوضع الصامت (عندما تسبق ':' سلسلة optstring)، يؤدي غياب الوسيط إلى ضبط getopts للمتغير varname على : وOPTARG على حرف الخيار — وهذا مثالي لعرض رسالة خطأ موجهة.

#!/usr/bin/env bash
# Demonstrate OPTARG with a file-processing script

while getopts ':i:o:' opt; do
  case "$opt" in
    i) INPUT="$OPTARG" ;;
    o) OUTPUT="$OPTARG" ;;
    :) echo "Error: option -$OPTARG needs a value" >&2; exit 1 ;;
    \?) echo "Error: unknown flag -$OPTARG" >&2; exit 1 ;;
  esac
done

echo "Input  : ${INPUT:-<not set>}"
echo "Output : ${OUTPUT:-<not set>}"

تجاوز الخيارات باستخدام OPTIND

بعد انتهاء getopts، يحتفظ OPTIND بفهرس أول وسيط ليس خيارًا. استخدموا shift لإزالة جميع الخيارات التي تمت معالجتها، بحيث تشير $1 و$2… إلى المعاملات الموضعية المتبقية (مثل أسماء الملفات).

والصيغة الاصطلاحية هي دائمًا:

shift $((OPTIND - 1))

بعد الإزاحة، لا تحتوي $@ إلا على الوسائط التي لم تكن رايات — أي معاملات الأمر.

#!/usr/bin/env bash
# Shows OPTIND shift and leftover positional args

VERBOSE=0
while getopts ':vn:' opt; do
  case "$opt" in
    v) VERBOSE=1 ;;
    n) COUNT="$OPTARG" ;;
    :) echo "Error: -$OPTARG requires an argument" >&2; exit 1 ;;
    \?) echo "Error: unknown option -$OPTARG" >&2; exit 1 ;;
  esac
done
shift $((OPTIND - 1))

echo "VERBOSE=$VERBOSE  COUNT=${COUNT:-1}"
echo "Remaining args: $*"

كتابة دالة الاستخدام

يوفر البرنامج النصي الاحترافي دائمًا دالة usage() تطبع رسالة مساعدة ثم تخرج. والاصطلاح هو:

  • الطباعة إلى stderr (واصف الملف 2) حتى لا تلوّث المخرجات الممررة عبر pipe
  • الخروج بالرمز 0 عند استخدام -h / --help، وبالرمز 1 عند الاستخدام غير الصحيح
  • استدعاء usage 1 من مسارات الخطأ، وusage 0 من معالج -h
#!/usr/bin/env bash

usage() {
  cat >&2 <<EOF
Usage: $(basename "$0") [-v] [-n COUNT] [-o FILE] [FILE...]

Options:
  -v          Verbose output
  -n COUNT    Repeat COUNT times (default: 1)
  -o FILE     Write output to FILE
  -h          Show this help
EOF
  exit "${1:-0}"
}

while getopts ':vn:o:h' opt; do
  case "$opt" in
    v) VERBOSE=1 ;;
    n) COUNT="$OPTARG" ;;
    o) OUTFILE="$OPTARG" ;;
    h) usage 0 ;;
    :) echo "Error: -$OPTARG requires a value" >&2; usage 1 ;;
    \?) echo "Error: unknown option -$OPTARG" >&2; usage 1 ;;
  esac
done
shift $((OPTIND - 1))
echo "Parsed OK — verbose=${VERBOSE:-0} count=${COUNT:-1} out=${OUTFILE:--}"

القيم الافتراضية والتحقق

بعد التحليل، تحقّقوا من القيم الافتراضية واضبطوها قبل تنفيذ أي عمل فعلي. افصلوا مرحلة التحليل (الحلقة) عن مرحلة المنطق. فهذا يجعل قراءة القسمين واختبارهما أسهل.

  • استخدموا ${VAR:-default} للقيم الافتراضية المضمنة
  • تحققوا من الوسائط الرقمية باستخدام تعبير نمطي أو فحص حسابي
  • تحققوا من توفير الخيارات المطلوبة فعلًا
#!/usr/bin/env bash

usage() { echo "Usage: $(basename "$0") -n COUNT [-v]" >&2; exit 1; }

VERBOSE=0
COUNT=''

while getopts ':n:v' opt; do
  case "$opt" in
    n) COUNT="$OPTARG" ;;
    v) VERBOSE=1 ;;
    :) echo "Error: -$OPTARG needs a value" >&2; usage ;;
    \?) echo "Error: -$OPTARG unknown" >&2; usage ;;
  esac
done
shift $((OPTIND - 1))

# Validation phase
[[ -z "$COUNT" ]] && { echo "Error: -n COUNT is required" >&2; usage; }
[[ "$COUNT" =~ ^[0-9]+$ ]] || { echo "Error: COUNT must be a positive integer" >&2; usage; }

for (( i=1; i<=COUNT; i++ )); do
  [[ $VERBOSE -eq 1 ]] && echo "Iteration $i of $COUNT"
  echo "Hello, world!"
done

دمج الرايات في سطر الأوامر

يتعامل getopts تلقائيًا مع الرايات القصيرة المدمجة المكتوبة من دون مسافات، وفق اصطلاح Unix المعتمد:

  • -v -q مكافئة لـ -vq
  • -n 5 -v مكافئة لـ -n5 -v أو -vn5

لا تحتاجون إلى كتابة أي كود إضافي لدعم ذلك — إذ يمر getopts تلقائيًا على كل حرف من سلسلة الخيارات المدمجة. وهذا سبب رئيسي آخر لاستخدام getopts بدلًا من المعالجة اليدوية.

#!/usr/bin/env bash
# Test combined flag parsing
# Run as:  bash script.sh -vq -n3

VERBOSE=0; QUIET=0; COUNT=1

while getopts ':vqn:' opt; do
  case "$opt" in
    v) VERBOSE=1 ;;
    q) QUIET=1 ;;
    n) COUNT="$OPTARG" ;;
    :) echo "Error: -$OPTARG needs value" >&2; exit 1 ;;
    \?) echo "Error: unknown -$OPTARG" >&2; exit 1 ;;
  esac
done
shift $((OPTIND - 1))

echo "verbose=$VERBOSE quiet=$QUIET count=$COUNT"

معالجة الفاصل ذي الشرطتين

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

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

وهذا مهم للبرامج النصية التي تتعامل مع أسماء ملفات قد تبدأ بشرطة، مثل:

myscript.sh -v -- -strangefile.txt
#!/usr/bin/env bash
# Demonstrate -- separator
# Run as:  bash script.sh -v -- file1.txt -oddname.txt

VERBOSE=0
while getopts ':v' opt; do
  case "$opt" in
    v) VERBOSE=1 ;;
    \?) echo "Unknown option -$OPTARG" >&2; exit 1 ;;
  esac
done
shift $((OPTIND - 1))   # removes -v and the '--' separator

echo "Verbose: $VERBOSE"
echo "Files to process:"
for f in "$@"; do
  echo "  -> $f"
done

تغليف getopts في دالة مكتبة

في البرامج النصية المعيارية، يمكنكم تغليف getopts داخل دالة parse_args() تضبط متغيرات عامة (أو متغيرات nameref). وهذا يحافظ على نظافة main() ويتيح استيراد محلل الوسائط من برامج نصية أخرى.

القواعد الأساسية لهذا النمط:

  • صرّحوا عن متغيرات الخيارات قبل استدعاء الدالة
  • استخدموا متغيرات global أو مرّروا القيم عبر nameref (declare -n)
  • أعيدوا رمز خروج غير صفري عند الإدخال غير الصحيح حتى يتمكن main من الاستجابة
#!/usr/bin/env bash

# Global option variables
VERBOSE=0; OUTPUT=''; COUNT=1

parse_args() {
  local opt
  while getopts ':vn:o:h' opt; do
    case "$opt" in
      v) VERBOSE=1 ;;
      n) COUNT="$OPTARG" ;;
      o) OUTPUT="$OPTARG" ;;
      h) echo "Usage: $(basename "$0") [-v] [-n N] [-o FILE]"; exit 0 ;;
      :) echo "Error: -$OPTARG needs a value" >&2; return 1 ;;
      \?) echo "Error: unknown option -$OPTARG" >&2; return 1 ;;
    esac
  done
  shift $((OPTIND - 1))
  ARGS=("$@")   # leftover positional args stored in array
}

main() {
  parse_args "$@" || exit 1
  echo "verbose=$VERBOSE count=$COUNT output=${OUTPUT:--} args=${ARGS[*]}"
}

main "$@"

مثال واقعي متكامل: مؤرشف سجلات

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

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

#!/usr/bin/env bash
# archive_logs.sh — compress and move logs older than N days

set -euo pipefail

DESTDIR='/tmp/log_archive'
DAYS=30
VERBOSE=0

usage() {
  cat >&2 <<EOF
Usage: $(basename "$0") [-v] [-d DAYS] [-o DIR] SOURCE_DIR

  -d DAYS   Archive logs older than DAYS (default: 30)
  -o DIR    Destination directory (default: /tmp/log_archive)
  -v        Verbose output
  -h        Show this help
EOF
  exit "${1:-0}"
}

while getopts ':d:o:vh' opt; do
  case "$opt" in
    d) DAYS="$OPTARG" ;;
    o) DESTDIR="$OPTARG" ;;
    v) VERBOSE=1 ;;
    h) usage 0 ;;
    :) echo "Error: -$OPTARG requires a value" >&2; usage 1 ;;
    \?) echo "Error: unknown option -$OPTARG" >&2; usage 1 ;;
  esac
done
shift $((OPTIND - 1))

# Validation
[[ $# -lt 1 ]] && { echo "Error: SOURCE_DIR is required" >&2; usage 1; }
[[ "$DAYS" =~ ^[0-9]+$ ]] || { echo "Error: DAYS must be numeric" >&2; exit 1; }
SOURCE="$1"
[[ -d "$SOURCE" ]] || { echo "Error: '$SOURCE' is not a directory" >&2; exit 1; }

mkdir -p "$DESTDIR"
[[ $VERBOSE -eq 1 ]] && echo "Archiving logs older than $DAYS days from $SOURCE to $DESTDIR"

find "$SOURCE" -name '*.log' -mtime "+$DAYS" -print | while read -r f; do
  gzip -c "$f" > "$DESTDIR/$(basename "$f").gz"
  [[ $VERBOSE -eq 1 ]] && echo "  archived: $f"
done

echo "Done."

اختبار سريع: optstring في getopts

اقرأوا استدعاء getopts التالي واختاروا الوصف الصحيح لسلوكه:

while getopts ':f:vq' opt; do

مراجعة الدرس: إتقان getopts

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

  • بنية optstring — الحروف التي لا تتبعها نقطتان هي رايات منطقية؛ وتعني النقطتان بعد الحرف أنه يتطلب وسيطًا؛ أما النقطتان في البداية فتفعّلان وضع الأخطاء الصامت.
  • OPTARG — يحتفظ تلقائيًا بقيمة الوسيط للخيارات التي تتطلب وسيطًا.
  • OPTIND — استخدموا shift $((OPTIND - 1)) بعد الحلقة لإتاحة المعاملات الموضعية المتبقية في $@.
  • وضع الأخطاء الصامت — يُفضَّل في بيئة الإنتاج؛ عالجوا بأنفسكم حالتي : (وسيط مفقود) و\? (خيار غير معروف) للتحكم الكامل.
  • دالة usage() — اكتبوا واحدة دائمًا؛ اطبعوا إلى stderr، واخرجوا بالرمز 0 عند -h، وبالرمز 1 عند الأخطاء.
  • الرايات المدمجة — يتعامل getopts مع -vq و-n5 تلقائيًا من دون كود إضافي.
  • النمط المعياري — غلّفوا getopts داخل دالة parse_args() لكتابة برامج نصية نظيفة قابلة لإعادة الاستخدام.

إن إتقان getopts يحوّل برامجكم النصية من أدوات مخصصة لغرض واحد إلى برامج CLI موثوقة وسهلة الاستخدام، تلتزم باصطلاحات Unix.

الأسئلة الشائعة

هل درس «تحليل الأعلام والوسائط باستخدام getopts» مجاني؟

نعم — نص درس «تحليل الأعلام والوسائط باستخدام getopts» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة DevOps Bootcamp، انتقل إلى CoddyKit PRO. تتضمن دورة DevOps Bootcamp 4 دروس في المجموع.

ماذا ستتعلم في «تحليل الأعلام والوسائط باستخدام getopts»؟

نفّذ واجهات سطر أوامر احترافية باستخدام getopts للخيارات القصيرة والوسائط المطلوبة ورسائل الاستخدام. تتمرن على DevOps Bootcamp مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.

هل أحتاج إلى خبرة سابقة لأبدأ DevOps Bootcamp؟

لا تُشترط خبرة سابقة. DevOps Bootcamp على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 3 من أصل 4.

كم من الوقت يستغرق درس «تحليل الأعلام والوسائط باستخدام getopts»؟

معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.

هل يمكنني كتابة وتشغيل أكواد في درس DevOps Bootcamp هذا؟

نعم. كل درس في DevOps Bootcamp يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.

جميع الدروس في هذه الدورة

  1. تصميم الدوال باستخدام النطاق المحلي ورموز الإرجاع
  2. بناء مكتبات Bash قابلة لإعادة الاستخدام وتحميلها
  3. تحليل الأعلام والوسائط باستخدام getopts
  4. تمرير المصفوفات والخرائط الترابطية بين الدوال
← العودة إلى DevOps Bootcamp