برمجة الصدفة والأتمتة

أول سكريبت باش لك

18 دقيقة الدرس 1 من 28

أول سكريبت باش لك

كل نظام إنتاج ستعمل عليه يشغّل سكريبتات Shell — مهام النسخ الاحتياطي، وخطاطيف النشر، وفحوصات الصحة، وتدوير السجلات، وخطوات خط CI. Bash ليست لغة لعبة تتعلمها مرة وتنساها؛ إنها الغراء الذي يربط البنية التحتية معًا في شركات كـ Google وMeta وAmazon. يبني هذا الدرس الأساس: كيف يُهيكَل السكريبت، وكيف يجده Shell وينفذه، والعادات التي تميز ملف أتمتة من مستوى الإنتاج عن سطر أوامر مؤقت.

ما هو سكريبت Shell؟

سكريبت Shell هو ملف نصي عادي يحتوي على تسلسل من الأوامر يقرأها الـ Shell — وأكثره شيوعًا bash — وينفذها سطرًا بسطر. لا توجد خطوة ترجمة (compile)؛ المُفسِّر يقرأ ملفك مباشرة. تلك البساطة هي قوته وخطره: أمر خاطئ في سكريبت إنتاج يُنفَّذ فورًا، دون محلل أنواع ليحذرك.

سطر Shebang

يجب أن يعلن أول سطر في كل سكريبت عن المُفسِّر الذي سيشغّله. هذا التسلسل المكوّن من حرفين #! متبوعًا بمسار المُفسِّر يُسمى shebang (ويُكتب أيضًا hashbang).

#!/usr/bin/env bash # هذا تعليق — يتجاهله الـ Shell

لماذا /usr/bin/env bash وليس /bin/bash؟ على معظم خوادم Linux يعمل /bin/bash بشكل جيد، لكن macOS وAlpine Linux وبعض صور الحاويات البسيطة تضع Bash في مسارات مختلفة. استخدام env يُفوِّض البحث إلى PATH الخاص بالنظام، مما يجعل الـ shebang قابلًا للنقل بين البيئات — خاصية بالغة الأهمية للسكريبتات التي تعمل على أجهزة المطورين ومُشغِّلات CI وخوادم الإنتاج على حد سواء.

ممارسة الشركات الكبرى: يُلزم دليل أسلوب Shell الداخلي في Google باستخدام #!/usr/bin/env bash لجميع السكريبتات المحمولة. احتفظ بـ #!/bin/bash فقط عندما تكون متأكدًا من بيئة النشر وتحتاج المسار الصريح لأسباب أمنية (مثل الحاويات المقيدة التي يكون فيها PATH محدودًا عمدًا).

إذا غاب الـ shebang، يعود kernel إلى /bin/sh — وهو على Debian/Ubuntu يكون dash وليس Bash. ستنكسر تركيبة Bash الخاصة بك (arrays، [[، local، استبدال العمليات) بصمت. دائمًا أدرج الـ shebang.

هيكل السكريبت: تشريح سكريبت إنتاج

السكريبت المهيكل جيدًا يُقرأ فورًا من أي شخص في فريقك — بمن فيهم المهندس المناوب الساعة الثالثة صباحًا الذي لم يرَ كودك من قبل.

#!/usr/bin/env bash # ============================================================= # deploy-check.sh — فحص ما قبل الإطلاق قبل الإصدار # المؤلف : ops-team@example.com # تاريخ : 2025-01-15 # الاستخدام: ./deploy-check.sh [environment] # ============================================================= # --- الإعداد ------------------------------------------- ENVIRONMENT="${1:-staging}" HEALTH_URL="https://${ENVIRONMENT}.example.com/health" TIMEOUT=10 # --- المنطق الرئيسي ------------------------------------------- echo "تشغيل الفحص المسبق لـ: ${ENVIRONMENT}" echo "نقطة النهاية: ${HEALTH_URL}" # (بقية المنطق هنا) echo "تم."

لاحظ الهيكل: shebang، كتلة رأس تحتوي الغرض والاستخدام، قسم إعداد، ثم المنطق. يستغرق هذا الترتيب 30 ثانية للكتابة ويوفر على المهندس التالي 30 دقيقة من التخمين.

جعل السكريبت قابلًا للتنفيذ

الملف النصي لا يمكن تشغيله حتى تمنحه إذن التنفيذ. الأمر المعياري هو:

# منح إذن التنفيذ للمالك (الأكثر شيوعًا) chmod +x deploy-check.sh # أكثر دقة: تنفيذ المالك فقط (لا مجموعة ولا جميع) chmod 700 deploy-check.sh # التحقق من أذونات الملف ls -l deploy-check.sh # الناتج: -rwx------ 1 you staff 312 Jan 15 10:00 deploy-check.sh

نموذج الأذونات مهم في الإنتاج. سكريبت يعمل بصلاحيات root وقابل للكتابة من الجميع يُعدّ ثغرة لرفع الامتيازات. للسكريبتات الآلية للنظام (مهام cron، خدمات systemd)، استخدم chmod 700 وتأكد أن الملف مملوك للحساب الخدمي الصحيح — وليس root ما لم يكن ذلك ضروريًا للغاية.

كيفية تشغيل سكريبت

هناك ثلاث طرق مختلفة لتنفيذ سكريبت، والفرق بينها ليس تافهًا:

  • ./deploy-check.sh — تشغيل السكريبت في subshell. يقرأ kernel الـ shebang، يولّد عملية Bash جديدة، وشِلك الحالي لا يتأثر. هذه الطريقة الصحيحة لتشغيل معظم السكريبتات.
  • bash deploy-check.sh — استدعاء Bash صريحًا، يتجاوز الـ shebang. مفيد عندما لا يكون الملف قابلًا للتنفيذ بعد أو عند التنقيح. يعمل أيضًا في subshell.
  • source deploy-check.sh (أو . deploy-check.sh) — تشغيل السكريبت في عملية الـ shell الحالية، لا subshell. تعيينات المتغيرات وأوامر cd تؤثر على جلستك الحالية. يُستخدم لسكريبتات إعداد البيئة (مثل تفعيل virtualenv، وتحميل الأسرار من ملف).
فخ الإنتاج — source بدلًا من تنفيذ: إذا استدعى سكريبت مُصدَر أمر exit، فإنه يغلق جلسة طرفيتك بأكملها وليس مجرد السكريبت. إذا أزال unset متغيرًا تعتمد عليه، فذلك المتغير مفقود من شِلك. قم بـ source للسكريبت فقط عندما تريد صراحةً أن يعدّل بيئتك.

تدفق تنفيذ السكريبت: كيف يقرأ Kernel ملفك

Shell script execution flow You type ./script.sh Kernel reads first 2 bytes (#!) Spawns interpreter /usr/bin/env bash Bash reads & runs each line in order Shell receives exec syscall Checks execute permission bit PATH lookup via env command Subshell — your session unchanged
كيف يعالج Kernel سكريبت Bash من الاستدعاء إلى التنفيذ.

أول سكريبت حقيقي لك

لنكتب سكريبتًا سيستخدمه مهندس DevOps فعلًا: ملخص معلومات النظام الذي يمكن تشغيله كفحص مسبق قبل النشر.

#!/usr/bin/env bash # ============================================================= # sysinfo.sh — طباعة لقطة سريعة للنظام # الاستخدام: ./sysinfo.sh # ============================================================= echo "=== لقطة النظام ===" echo "اسم المضيف : $(hostname)" echo "نظام التشغيل: $(uname -s) $(uname -r)" echo "وقت التشغيل : $(uptime -p 2>/dev/null || uptime)" echo "القرص : $(df -h / | awk 'NR==2{print $5 " used on " $1}')" echo "الذاكرة : $(free -h 2>/dev/null | awk '/^Mem:/{print $3 " used / " $2 " total"}')" echo "متوسط الحمل: $(cat /proc/loadavg 2>/dev/null | awk '{print $1,$2,$3}')" echo "===================="

احفظه بوصفه sysinfo.sh، نفّذ chmod +x sysinfo.sh، ثم شغّله بـ ./sysinfo.sh. ستفهم فورًا لماذا سكريبتات Shell لا غنى عنها: في ثمانية أسطر جمعت مخرجات من ستة مصادر نظام مختلفة في تقرير متماسك.

نصيحة العمل — استخدم مجلد scripts: في المشاريع الحقيقية، ضع سكريبتات الأتمتة في مجلد scripts/ على مستوى الجذر ملتزمًا بالمستودع. سمِّ السكريبتات بأفعال (build.sh، deploy.sh، check-health.sh). أضف README يوثّق غرض كل سكريبت ومتغيرات البيئة المطلوبة. هذا هو الممارسة المعيارية في شركات ذات قواعد كود بنية تحتية كبيرة.

التعليقات والتوثيق الذاتي

تبدأ التعليقات في Bash بـ # وتمتد حتى نهاية السطر. خلافًا لكثير من اللغات، تعيش سكريبتات Shell في الغالب لسنوات مع تعديلات قليلة، يلمسها مهندسون لم يكونوا في الفريق حين كُتبت. عامل التعليقات كوثائق تشغيلية:

  • اشرح لماذا وليس ماذا. # إعادة المحاولة 3 مرات للتعامل مع أخطاء DNS المؤقتة مفيد. # حلقة 3 مرات ليس كذلك.
  • وثّق التبعيات الخارجية: الأدوات التي يجب تثبيتها، ومتغيرات البيئة التي يجب ضبطها.
  • ضع علامة على أي حلول بديلة غير واضحة مع ملاحظة تشرح المشكلة الجوهرية.

أنماط الفشل الشائعة

معرفة ما يسوء قبل حدوثه في الإنتاج هي نصف العمل:

  • Permission denied عند التنفيذ — نسيت chmod +x. الحل: chmod +x script.sh.
  • Bad interpreter: No such file or directory — مسار الـ shebang خاطئ، أو عُدِّل السكريبت على Windows وبه نهايات سطر CRLF (\r\n). صحّح نهايات السطر بـ sed -i 's/\r//' script.sh أو dos2unix script.sh.
  • Command not found عند التشغيل عبر cron أو systemd — الـ shells غير التفاعلية لها PATH محدود. الحل: حدد PATH صراحةً بالقرب من أعلى السكريبت (PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin).
  • السكريبت يعمل كمستخدمك لكن يفشل كحساب الخدمة — حساب الخدمة يفتقر إلى إذن قراءة ملف يحتاجه سكريبتك، أو لا يوجد مجلده الرئيسي. دائمًا اختبر السكريبتات تحت نفس المستخدم الذي سيشغّلها في الإنتاج.

بهذه الأسس في مكانها — shebang، الأذونات، أنماط التنفيذ، والهيكل — لديك كل ما تحتاجه لكتابة سكريبتات يستطيع زملاؤك قراءتها، ومناوبتك تنقيحها، وأنظمة الأتمتة تشغيلها بشكل موثوق. كل درس لاحق في هذه الوحدة يبني على هذا الأساس.