بايثون بعد الأساسيات 4: بناء برنامج سطر أوامر CLI بسيط في Python

بناء برنامج سطر أوامر CLI بسيط في Python بعد تعلم الأساسيات

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

كلمة CLI هي اختصار لعبارة Command Line Interface، وتعني واجهة سطر الأوامر. بدل أن يستخدم الشخص أزرارًا ونوافذ رسومية، يتعامل مع البرنامج من خلال أوامر يكتبها في Terminal أو CMD أو PowerShell.

في هذا الدرس من سلسلة بايثون بعد الأساسيات على موقع بايثون العرب سنتعلم بناء برنامج سطر أوامر بسيط في Python خطوة بخطوة. سنبدأ بفكرة بسيطة باستخدام input()، ثم ننتقل إلى طريقة أفضل باستخدام مكتبة argparse المدمجة مع Python، ثم ننظم المشروع ونضيف رسائل أوضح للمستخدم.

{getToc} $title={محتوى المقال}

الفكرة ببساطة: برنامج CLI هو برنامج تشغله من Terminal وتتحكم فيه بالأوامر والخيارات. في البداية يمكنك استخدام input()، لكن للمشاريع الأفضل استخدم argparse. {alertInfo}

ما هو برنامج CLI في Python؟

برنامج CLI هو برنامج يعمل من خلال سطر الأوامر. مثلًا بدل أن تفتح نافذة فيها زر "تشغيل"، تكتب أمرًا مثل:

python main.py

أو:

python main.py --name Ali

أو:

python main.py add "تعلم Python"

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


شرح فكرة برنامج CLI في Python وكيف يتعامل المستخدم معه من Terminal

لماذا نتعلم بناء برامج CLI؟

تعلم بناء برامج سطر الأوامر يساعدك على فهم Python بطريقة عملية أكثر، لأنك ستبدأ في التفكير مثل المطورين:

  • كيف يستقبل البرنامج أوامر من المستخدم؟
  • كيف أعالج الخيارات المختلفة؟
  • كيف أرتب الملفات داخل المشروع؟
  • كيف أجعل البرنامج واضحًا عند الاستخدام؟
  • كيف أتعامل مع الأخطاء بدل توقف البرنامج فجأة؟
  • كيف أجعل الأداة قابلة للتطوير لاحقًا؟

برامج CLI ليست للخبراء فقط. هي من أفضل المشاريع الصغيرة بعد تعلم الأساسيات؛ لأنها تجمع بين الدوال، الشروط، القواميس، القوائم، الملفات، ورسائل الأخطاء في مشروع واحد.

أمثلة على أدوات CLI حقيقية

ربما استخدمت من قبل أوامر مثل:

python --version
pip install requests
git status
npm install
django-admin startproject mysite

كل هذه أمثلة على أدوات تعمل من سطر الأوامر. أنت أيضًا يمكنك بناء أدوات صغيرة بنفس الفكرة باستخدام Python.

متى أستخدم CLI بدل الواجهة الرسومية؟

استخدم CLI عندما تريد أداة:

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

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

المرحلة الأولى: برنامج CLI بسيط باستخدام input

قبل أن ندخل إلى argparse، لنبدأ بطريقة بسيطة يعرفها أغلب المبتدئين: input().

سنكتب برنامجًا يطلب اسم المستخدم ثم يطبع رسالة ترحيب.

name = input("اكتب اسمك: ")

print("مرحبًا", name)

عند التشغيل:

python main.py

سيطلب منك البرنامج إدخال الاسم:

اكتب اسمك: Ali
مرحبًا Ali

هذه طريقة سهلة، لكنها ليست دائمًا الأفضل لأدوات سطر الأوامر؛ لأن المستخدم لا يستطيع تمرير الخيارات مباشرة مع الأمر.

ما مشكلة input في برامج CLI؟

استخدام input() مفيد للتفاعل البسيط، لكنه قد يكون محدودًا في الأدوات العملية. مثلًا، لا يمكنك تشغيل البرنامج بهذا الشكل:

python main.py --name Ali

لأن البرنامج ينتظر منك إدخالًا بعد التشغيل. في أدوات CLI الأفضل أن يستطيع المستخدم تمرير القيم مباشرة مع الأمر.

لهذا نستخدم مكتبة argparse.

ما هي مكتبة argparse؟

مكتبة argparse مكتبة مدمجة مع Python، أي لا تحتاج إلى تثبيتها. وظيفتها أن تساعدك على استقبال أوامر وخيارات من سطر الأوامر.

بدل أن تجعل البرنامج يسأل المستخدم:

اكتب اسمك:

يمكنك جعله يقبل الأمر هكذا:

python main.py --name Ali

ثم يقرأ البرنامج قيمة --name ويستخدمها.

أول برنامج CLI باستخدام argparse

أنشئ ملفًا باسم main.py واكتب:

import argparse

parser = argparse.ArgumentParser(
    description="برنامج ترحيب بسيط باستخدام Python CLI"
)

parser.add_argument(
    "--name",
    required=True,
    help="اسم المستخدم"
)

args = parser.parse_args()

print("مرحبًا", args.name)

شغل البرنامج:

python main.py --name Ali

الناتج:

مرحبًا Ali

استخدام argparse في Python لاستقبال أوامر وخيارات من سطر الأوامر

شرح الكود خطوة بخطوة

السطر الأول:

import argparse

نستورد مكتبة argparse.

ثم ننشئ كائنًا اسمه parser:

parser = argparse.ArgumentParser(
    description="برنامج ترحيب بسيط باستخدام Python CLI"
)

هذا الكائن مسؤول عن تعريف الخيارات وقراءة ما يكتبه المستخدم في Terminal.

ثم نضيف خيارًا:

parser.add_argument(
    "--name",
    required=True,
    help="اسم المستخدم"
)

معناه أن البرنامج يقبل خيارًا اسمه --name، وهذا الخيار مطلوب لأننا وضعنا required=True.

ثم نقرأ القيم:

args = parser.parse_args()

بعدها نستطيع الوصول إلى الاسم من خلال:

args.name

ميزة help في برامج CLI

من أجمل ميزات argparse أنها تنشئ صفحة مساعدة تلقائيًا.

جرّب:

python main.py --help

ستظهر لك رسالة توضح طريقة استخدام البرنامج والخيارات المتاحة.

هذا مهم جدًا؛ لأن برنامج CLI الجيد يجب أن يشرح نفسه للمستخدم.

إضافة خيار غير إجباري

لنفترض أننا نريد إضافة خيار --lang لتحديد لغة الرسالة، لكنه ليس إجباريًا.

import argparse

parser = argparse.ArgumentParser(
    description="برنامج ترحيب بسيط"
)

parser.add_argument("--name", required=True, help="اسم المستخدم")
parser.add_argument("--lang", default="ar", help="لغة الرسالة: ar أو en")

args = parser.parse_args()

if args.lang == "en":
    print("Hello", args.name)
else:
    print("مرحبًا", args.name)

التشغيل بالعربية:

python main.py --name Ali

الناتج:

مرحبًا Ali

التشغيل بالإنجليزية:

python main.py --name Ali --lang en

الناتج:

Hello Ali

تحديد قيم مسموحة باستخدام choices

بدل أن نترك المستخدم يكتب أي قيمة في --lang، يمكننا تحديد القيم المسموحة:

parser.add_argument(
    "--lang",
    choices=["ar", "en"],
    default="ar",
    help="لغة الرسالة"
)

إذا كتب المستخدم قيمة غير مسموحة، ستعرض argparse رسالة خطأ واضحة.

بناء مشروع CLI منظم

بدل وضع كل شيء عشوائيًا، دعنا ننشئ مجلد مشروع بسيط:

simple_cli/
│
├── main.py
├── README.md
└── data/
    └── tasks.txt

في البداية يمكن أن يكون المشروع بملف واحد فقط، لكن التنظيم من الآن يساعدك عندما يكبر البرنامج.


هيكل مشروع Python بسيط لبناء برنامج CLI يحتوي على main.py و README

مشروع عملي: برنامج مهام CLI بسيط

الآن سنبني برنامجًا عمليًا صغيرًا لإدارة المهام من سطر الأوامر. البرنامج سيقوم بثلاث عمليات:

  • إضافة مهمة جديدة.
  • عرض كل المهام.
  • مسح كل المهام.

سنستخدم ملفًا نصيًا بسيطًا لتخزين المهام.

الفكرة العامة للبرنامج

نريد أن يعمل البرنامج بهذه الطريقة:

python main.py add "تعلم argparse"
python main.py list
python main.py clear

الأمر add يضيف مهمة، والأمر list يعرض المهام، والأمر clear يمسحها.

الكود الكامل لبرنامج المهام CLI

اكتب هذا الكود داخل main.py:

import argparse
from pathlib import Path


DATA_DIR = Path("data")
TASKS_FILE = DATA_DIR / "tasks.txt"


def prepare_storage():
    DATA_DIR.mkdir(exist_ok=True)
    TASKS_FILE.touch(exist_ok=True)


def add_task(task):
    prepare_storage()

    with TASKS_FILE.open("a", encoding="utf-8") as file:
        file.write(task + "\n")

    print("تمت إضافة المهمة:", task)


def list_tasks():
    prepare_storage()

    with TASKS_FILE.open("r", encoding="utf-8") as file:
        tasks = [line.strip() for line in file if line.strip()]

    if not tasks:
        print("لا توجد مهام حاليًا.")
        return

    print("قائمة المهام:")

    for index, task in enumerate(tasks, start=1):
        print(f"{index}. {task}")


def clear_tasks():
    prepare_storage()

    TASKS_FILE.write_text("", encoding="utf-8")

    print("تم مسح جميع المهام.")


def main():
    parser = argparse.ArgumentParser(
        description="برنامج مهام بسيط يعمل من سطر الأوامر"
    )

    subparsers = parser.add_subparsers(
        dest="command",
        required=True
    )

    add_parser = subparsers.add_parser("add", help="إضافة مهمة جديدة")
    add_parser.add_argument("task", help="نص المهمة")

    subparsers.add_parser("list", help="عرض المهام")
    subparsers.add_parser("clear", help="مسح كل المهام")

    args = parser.parse_args()

    if args.command == "add":
        add_task(args.task)

    elif args.command == "list":
        list_tasks()

    elif args.command == "clear":
        clear_tasks()


if __name__ == "__main__":
    main()

تشغيل برنامج المهام

لإضافة مهمة:

python main.py add "تعلم بناء CLI في Python"

الناتج:

تمت إضافة المهمة: تعلم بناء CLI في Python

لعرض المهام:

python main.py list

الناتج:

قائمة المهام:
1. تعلم بناء CLI في Python

لمسح المهام:

python main.py clear

الناتج:

تم مسح جميع المهام.

ما معنى subcommands في argparse؟

في برنامجنا استخدمنا أوامر فرعية مثل:

add
list
clear

هذه تسمى subcommands أو أوامر فرعية. وهي مفيدة عندما يكون البرنامج فيه أكثر من عملية.

مثلًا:

  • add لإضافة مهمة.
  • list لعرض المهام.
  • clear لمسح المهام.

وهذا يشبه أدوات حقيقية مثل:

git add
git commit
git status

لماذا استخدمنا pathlib؟

استخدمنا pathlib للتعامل مع المسارات بطريقة أوضح:

from pathlib import Path

ثم:

DATA_DIR = Path("data")
TASKS_FILE = DATA_DIR / "tasks.txt"

هذه الطريقة أفضل من كتابة المسار كسلسلة نصية طويلة، وتعمل بشكل أوضح مع Windows و Linux و macOS.

إذا لم تكن مرتاحًا مع pathlib بعد، راجع: شرح pathlib في Python للتعامل مع الملفات والمجلدات.

شرح دالة prepare_storage

الدالة:

def prepare_storage():
    DATA_DIR.mkdir(exist_ok=True)
    TASKS_FILE.touch(exist_ok=True)

تقوم بعملين:

  • إنشاء مجلد data إذا لم يكن موجودًا.
  • إنشاء ملف tasks.txt إذا لم يكن موجودًا.

استخدمنا exist_ok=True حتى لا يظهر خطأ إذا كان المجلد أو الملف موجودًا مسبقًا.

شرح دالة add_task

هذه الدالة تضيف مهمة إلى الملف:

def add_task(task):
    prepare_storage()

    with TASKS_FILE.open("a", encoding="utf-8") as file:
        file.write(task + "\n")

استخدمنا الوضع "a" لأنه يعني append، أي الإضافة في نهاية الملف بدل مسح المحتوى القديم.

شرح دالة list_tasks

هذه الدالة تقرأ كل المهام من الملف:

with TASKS_FILE.open("r", encoding="utf-8") as file:
    tasks = [line.strip() for line in file if line.strip()]

استخدمنا strip() لحذف الفراغات ونهاية السطر \n.

ثم عرضنا المهام بالأرقام:

for index, task in enumerate(tasks, start=1):
    print(f"{index}. {task}")

الدالة enumerate() تساعدنا على الحصول على رقم العنصر وقيمته في نفس الوقت.

شرح دالة clear_tasks

هذه الدالة تمسح محتوى الملف:

TASKS_FILE.write_text("", encoding="utf-8")

كتابة نص فارغ داخل الملف تعني حذف كل المهام القديمة.

إضافة تأكيد قبل المسح

قد يكون من الأفضل أن تطلب تأكيدًا من المستخدم قبل مسح كل المهام.

def clear_tasks():
    prepare_storage()

    answer = input("هل أنت متأكد من مسح كل المهام؟ yes/no: ")

    if answer.lower() != "yes":
        print("تم إلغاء العملية.")
        return

    TASKS_FILE.write_text("", encoding="utf-8")
    print("تم مسح جميع المهام.")

هنا جمعنا بين argparse و input(). لا مانع من ذلك عند الحاجة.

إضافة أمر count لحساب عدد المهام

يمكنك تطوير البرنامج بإضافة أمر جديد اسمه count.

أولًا أضف دالة:

def count_tasks():
    prepare_storage()

    with TASKS_FILE.open("r", encoding="utf-8") as file:
        tasks = [line for line in file if line.strip()]

    print("عدد المهام:", len(tasks))

ثم أضف الأمر:

subparsers.add_parser("count", help="عرض عدد المهام")

ثم داخل الشروط:

elif args.command == "count":
    count_tasks()

التشغيل:

python main.py count

التعامل مع الأخطاء في برنامج CLI

برنامج CLI الجيد لا يجب أن يعرض للمستخدم رسائل أخطاء طويلة دائمًا. أحيانًا نحتاج إلى رسائل واضحة.

مثال: عند محاولة قراءة ملف قد تظهر أخطاء مثل:

  • FileNotFoundError
  • PermissionError
  • UnicodeDecodeError

في برنامجنا أنشأنا الملف تلقائيًا لتجنب FileNotFoundError. لكن في برامج أكبر يجب أن تتعامل مع الأخطاء المتوقعة.

try:
    content = TASKS_FILE.read_text(encoding="utf-8")
except PermissionError:
    print("لا توجد صلاحية لقراءة ملف المهام.")

راجع أيضًا: شرح try و except في Python للمبتدئين و حل خطأ PermissionError في Python عند فتح الملفات.

استخدام exit code في برامج CLI

في الأدوات العملية، قد تحتاج إلى إرجاع رمز خروج يوضح هل نجح البرنامج أم فشل. عادة:

  • 0 يعني نجاح.
  • أي رقم غير 0 يعني وجود مشكلة.

مثال بسيط:

import sys

if not TASKS_FILE.exists():
    print("ملف المهام غير موجود.")
    sys.exit(1)

sys.exit(0)

هذه فكرة متقدمة قليلًا، لكنها مهمة إذا أردت بناء أدوات يستخدمها الآخرون أو تعمل داخل سكربتات تلقائية.

كيف تجعل برنامجك أسهل في الاستخدام؟

برنامج CLI الجيد يجب أن يكون واضحًا. لذلك اهتم بـ:

  • اسم أمر واضح.
  • وصف قصير داخل description.
  • رسائل help مفهومة.
  • رسائل نجاح واضحة.
  • رسائل خطأ لا تخيف المستخدم.
  • أمثلة استخدام داخل README.

مثال README بسيط:

# Simple CLI Tasks

برنامج مهام بسيط باستخدام Python.

## التشغيل

إضافة مهمة:

python main.py add "تعلم Python"

عرض المهام:

python main.py list

مسح المهام:

python main.py clear

أفضل ممارسات بناء CLI في Python


أفضل ممارسات بناء برامج CLI في Python وتنظيم الأوامر والرسائل
  • ابدأ ببرنامج صغير وواضح.
  • استخدم argparse للأدوات العملية بدل الاعتماد الكامل على input().
  • اكتب أسماء أوامر مفهومة مثل add و list و clear.
  • استخدم --help وتأكد أن الرسائل واضحة.
  • افصل الكود إلى دوال بدل وضع كل شيء داخل مكان واحد.
  • استخدم pathlib للتعامل مع الملفات والمجلدات.
  • استخدم encoding="utf-8" عند قراءة وكتابة النصوص.
  • تعامل مع الأخطاء المتوقعة برسائل بسيطة.
  • لا تجعل البرنامج يمسح بيانات مهمة بدون تأكيد.
  • اكتب ملف README يشرح طريقة الاستخدام.

أخطاء شائعة عند بناء برنامج CLI

1. نسيان إضافة help

لا تجعل المستخدم يخمن طريقة تشغيل البرنامج. أضف وصفًا لكل خيار.

2. وضع كل الكود في مكان واحد

استخدم دوال مثل add_task() و list_tasks() و clear_tasks() حتى يبقى الكود واضحًا.

3. عدم التعامل مع الملفات بشكل آمن

استخدم with عند فتح الملفات، واستخدم encoding="utf-8" لتجنب مشاكل الترميز.

4. عدم اختبار الأوامر المختلفة

جرّب كل أمر:

python main.py --help
python main.py add "Test"
python main.py list
python main.py clear

5. استخدام أسماء أوامر غير واضحة

الأمر add أوضح من a للمبتدئين، و list أوضح من ls في البرامج التعليمية.

كيف تطور هذا المشروع لاحقًا؟

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

  • إضافة أمر لحذف مهمة محددة برقمها.
  • إضافة أمر لتعديل مهمة.
  • إضافة حالة للمهمة: مكتملة أو غير مكتملة.
  • حفظ البيانات في JSON بدل TXT.
  • حفظ البيانات في CSV.
  • إضافة تاريخ إنشاء المهمة.
  • إضافة ألوان للرسائل باستخدام مكتبات خارجية لاحقًا.
  • تحويل المشروع إلى حزمة قابلة للتثبيت.

يمكنك ربط هذا الدرس بدروس: شرح مكتبة json في Python و شرح ملفات CSV في Python إذا أردت تخزين المهام بطريقة منظمة أكثر.

تدريب عملي

بعد تطبيق البرنامج، حاول تنفيذ التعديلات التالية:

  1. أضف أمرًا جديدًا باسم count يعرض عدد المهام.
  2. أضف تأكيدًا قبل تنفيذ أمر clear.
  3. اجعل أمر add يرفض المهمة الفارغة.
  4. أضف ملف README.md فيه أمثلة تشغيل.
  5. جرّب تشغيل python main.py --help ولاحظ صفحة المساعدة.

حل مختصر: منع إضافة مهمة فارغة

يمكنك تعديل دالة add_task بهذا الشكل:

def add_task(task):
    task = task.strip()

    if not task:
        print("لا يمكن إضافة مهمة فارغة.")
        return

    prepare_storage()

    with TASKS_FILE.open("a", encoding="utf-8") as file:
        file.write(task + "\n")

    print("تمت إضافة المهمة:", task)

استخدمنا strip() لحذف الفراغات، ثم تحققنا هل النص فارغ أم لا.

روابط داخلية مفيدة من بايثون العرب

مصادر خارجية مفيدة للتوسع

الخلاصة

بناء برنامج سطر أوامر CLI بسيط في Python خطوة ممتازة بعد تعلم الأساسيات؛ لأنها تجمع بين الدوال، الشروط، الملفات، تنظيم المشروع، والتعامل مع مدخلات المستخدم بطريقة عملية.

بدأنا بطريقة بسيطة باستخدام input()، ثم تعلمنا استخدام argparse لاستقبال الخيارات والأوامر من Terminal. بعد ذلك بنينا برنامج مهام بسيط يدعم أوامر add و list و clear، وتعلمنا كيف ننظم المشروع ونتعامل مع الملفات باستخدام pathlib.

الخلاصة العملية: إذا أردت بناء أداة Python صغيرة تعمل من Terminal، ابدأ بـ argparse، قسّم الكود إلى دوال، أضف رسائل help واضحة، وتعامل مع الملفات والأخطاء بعناية. {alertSuccess}

أسئلة شائعة مع إجاباتها

ما معنى CLI في Python؟

يعني برنامج يعمل من خلال سطر الأوامر، حيث يكتب المستخدم أوامر وخيارات في Terminal لتشغيل وظائف البرنامج.

هل أحتاج مكتبة خارجية لبناء CLI في Python؟

لا. يمكنك استخدام مكتبة argparse المدمجة مع Python لبناء أدوات CLI جيدة بدون تثبيت مكتبات إضافية.

ما الفرق بين input و argparse؟

input() يطلب من المستخدم إدخال قيمة أثناء تشغيل البرنامج، أما argparse فيقرأ القيم والخيارات مباشرة من الأمر المكتوب في Terminal.

متى أستخدم argparse؟

استخدمه عندما تريد بناء أداة تقبل خيارات مثل --name أو أوامر مثل add و list.

هل برنامج CLI مناسب للمبتدئين؟

نعم، خصوصًا بعد تعلم الأساسيات. هو مشروع ممتاز للتدريب على الدوال والملفات والشروط وتنظيم الكود.

كيف أجعل برنامج CLI أكثر احترافية؟

أضف صفحة مساعدة واضحة، قسّم الكود إلى دوال، تعامل مع الأخطاء، واكتب ملف README يشرح طريقة التشغيل.

هل يمكن تخزين بيانات CLI في JSON أو CSV؟

نعم. في البداية استخدم ملف TXT بسيط، ثم يمكنك تطوير البرنامج لاحقًا ليستخدم JSON أو CSV حسب نوع البيانات.

إرسال تعليق

أحدث أقدم