لماذا سكربت؟
كل مجموعة أوامر تكتبها أكثر من مرّتين تستحقّ سكربتًا: نشر تطبيق، ونسخ احتياطي، وإعداد خادم جديد. السكربت ملف نصي فيه نفس الأوامر التي تكتبها في الطرفية، بالترتيب، مع متغيّرات وشروط وحلقات.
أول سكربت
#!/usr/bin/env bash
set -euo pipefail
echo "مرحبًا من السكربت"
echo "أنت في: $(pwd)"
- السطر الأول (shebang) يقول للنظام أي مفسّر يشغّل الملف.
#!/usr/bin/env bashتبحث عن bash فيPATH، فتعمل حتى لو لم يكن في/bin. والصيغة#!/bin/bashشائعة أيضًا. set -euo pipefailيجعل السكربت يتوقّف عند أول خطأ بدل أن يكمل وكأن شيئًا لم يحدث:-e: توقّف إذا فشل أي أمر.-u: توقّف عند استخدام متغيّر غير معرّف (يكشف الأخطاء الإملائية في الأسماء).-o pipefail: الأنبوب يفشل إذا فشل أي جزء منه، لا آخره فقط.
بدون هذا السطر، سكربت نشر يفشل في cd /app سيكمل ويشغّل باقي الأوامر في المجلّد الخطأ.
التشغيل
chmod +x hello.sh # اجعله قابلًا للتنفيذ (مرة واحدة)
./hello.sh # شغّله
bash hello.sh # أو مرّره لـ bash مباشرة (بلا حاجة لـ chmod)
المتغيّرات
name="Baraa" # بلا مسافات حول =
greeting="أهلًا $name" # التوسيع داخل التنصيص المزدوج
literal='أهلًا $name' # المفرد: حرفيًا كما هو
echo "$greeting" # أهلًا Baraa
echo "$literal" # أهلًا $name
echo "${name}_backup" # Baraa_backup : الأقواس تحدّد نهاية الاسم
ضع المتغيّرات بين علامات تنصيص دائمًا
file="my notes.txt"
touch "$file"
ls $file # ❌ يبحث عن ملفين: my و notes.txt
ls "$file" # ✅
بدون تنصيص، يقسم Bash قيمة المتغيّر عند المسافات، ويوسّع أي * فيها. هذا أشهر مصدر للأخطاء في السكربتات. القاعدة: اكتب "$var" دائمًا، إلا إذا كنت تقصد التقسيم فعلًا.
ناتج أمر في متغيّر
today=$(date +%F)
count=$(ls | wc -l)
echo "اليوم $today وفي المجلّد $count عنصرًا"
$(...) تشغّل الأمر وتضع مخرجه مكانها.
المدخلات والوسائط
#!/usr/bin/env bash
echo "اسم السكربت: $0"
echo "الوسيط الأول: ${1:-لا يوجد}" # قيمة افتراضية إن لم يُعطَ
echo "عدد الوسائط: $#"
echo "كل الوسائط: $*"
read -rp "ما اسمك؟ " username
echo "أهلًا $username"
./greet.sh سارة علي
# الوسيط الأول: سارة
# عدد الوسائط: 2
$1 و$2... الوسائط بالترتيب، و$# عددها. و${1:-قيمة} تعطي قيمة افتراضية. أما read -r فتقرأ سطرًا من المستخدم (-r تمنع تفسير الشرطة العكسية، و-p تعرض سؤالًا).
الحساب
a=7
b=3
echo $((a + b)) # 10
echo $((a / b)) # 2 : أعداد صحيحة فقط
echo $((a % b)) # 1
((a++))
echo "$a" # 8
Bash لا يتعامل مع الكسور. للكسور استخدم bc أو awk: awk 'BEGIN {print 7/3}'.
رمز الخروج
grep -q "root" /etc/passwd
echo $? # 0: نجح (وُجد)
grep -q "nobody-here-xyz" /etc/passwd
echo $? # 1: فشل (لم يُوجد)
كل أمر يُرجع رقمًا: 0 نجاح، وغيره فشل. و$? رمز آخر أمر. الشروط في الدرس التالي تعتمد على هذا بالكامل. وسكربتك نفسه ينتهي بـ exit 0 أو exit 1 لتعرف الأدوات الأخرى (CI مثلًا) هل نجح.
أخطاء شائعة
- مسافات حول
=:name = "x"خطأ؛ Bash يظنّnameأمرًا. - متغيّرات بلا تنصيص: تنكسر مع المسافات و
*في القيم. - التنصيص المفرد حين تريد التوسيع:
'$name'تبقى حرفيًا. - سكربت بلا
set -euo pipefail: يكمل بعد الأخطاء بصمت. ((n++))معset -e: حين تكونnصفرًا، قيمة التعبير صفر فيُعتبر "فشلًا" وينتهي السكربت بصمت. اكتبn=$((n + 1)).- ملف كُتب في Windows: نهايات أسطر
\r\nتعطيbad interpreter: /bin/bash^M. حوّله بـsed -i 's/\r$//' script.shأوdos2unix.
🎯 التالي: التحكّم في سكربتات Bash.