سكريبت bash للمبتدئين: أول سكريبت والمتغيرات والشروط والحلقات وcron
سكريبت Bash ملف نصي يحتوي على أوامر الواجهة، يبدأ سطره الأول بـ #!/bin/bash، ويحصل على صلاحية التشغيل عبر chmod +x ويُشغَّل بالشكل ./script.sh. تُستخدم في السكريبتات المتغيرات والوسائط $1 و$2 وشروط if والحلقات for وwhile، ويُضبط التشغيل الدوري عبر crontab -e.
سكريبت Bash ملف نصي عادي يحتوي على أوامر كنت ستكتبها في الطرفية واحدةً تلو الأخرى. يبدأ السكريبت بسطر shebang وهو #!/bin/bash، ويحصل على صلاحية التنفيذ عبر chmod +x، ويُشغَّل بالشكل ./script.sh. هذا الدليل مخصص للمبتدئين في سكريبتات bash، من السطر الأول حتى التشغيل المجدول: المتغيرات، والوسائط، والشروط، والحلقات، ومعالجة الأخطاء، وcron.
أول سكريبت bash في دقيقة
أنشئ الملف بأي محرر، مثل nano:
nano hello.sh
#!/bin/bash
# أول سكريبت: تحية ومعلومات بسيطة عن النظام
echo "مرحباً، $USER!"
echo "التاريخ اليوم: $(date +%Y-%m-%d)"
echo "أنت الآن في: $(pwd)"
احفظ الملف (Ctrl+O ثم Enter ثم Ctrl+X)، ثم امنحه صلاحية التشغيل وشغّله:
$ chmod +x hello.sh
$ ./hello.sh
مرحباً، alice!
التاريخ اليوم: 2026-10-12
أنت الآن في: /home/alice
الأسطر التي تبدأ بـ # تعليقات. والصيغة $(أمر) تضع مخرجات الأمر داخل النص مباشرةً.
Shebang: دور السطر الأول
يخبر السطر #!/bin/bash النظام بالمفسّر الذي يُنفّذ الملف. وبدونه يُشغَّل السكريبت بأي واجهة متاحة، وفي بعض الأنظمة يكون /bin/sh ليس bash بل dash الأبسط، وعندها لا تعمل بعض التراكيب.
وكثيراً ما يُستخدم أيضاً السطر #!/usr/bin/env bash: يبحث عن bash في PATH، وهذا مفيد إذا كان bash مثبتاً في مكان غير /bin.
كيف تشغّل السكريبت، ولماذا ./
هناك طريقتان:
./hello.sh: يحتاج إلى سطر shebang وإلى صلاحية التنفيذx. والبادئة./ضرورية لأن المجلد الحالي غير موجود فيPATH.bash hello.sh: لا يحتاج إلى صلاحية التنفيذ، لأن المفسّر محدد صراحةً.
إذا ظهرت لك رسالة command not found دون ./، وPermission denied دون chmod +x، فهذان هما السببان بالضبط. ولاستدعاء سكريبتاتك بالاسم من أي مكان، ضعها في ~/bin أو /usr/local/bin.
المتغيرات
يُعطى المتغير دون مسافات حول علامة =، ويُقرأ بالرمز $:
#!/bin/bash
name="backup"
dir="/var/backups"
today=$(date +%F)
echo "الملف: ${dir}/${name}-${today}.tar.gz"
الأقواس المعقوفة تفصل اسم المتغير عن النص الذي يليه. أما name = "backup" مع المسافات فخطأ: سيحاول bash تشغيل أمر اسمه name.
علامات الاقتباس مهمة
داخل علامات الاقتباس المزدوجة تُستبدل المتغيرات، أما داخل المفردة فلا. ويُفضَّل دائماً وضع المتغيرات بين علامات مزدوجة، وإلا فإن اسم الملف الذي يحتوي على مسافة سيتحول إلى وسيطين.
file="تقرير مهم.txt"
rm $file # خطأ: سيحاول حذف «تقرير» و«مهم.txt»
rm "$file" # صحيح
echo '$HOME' # يطبع $HOME حرفياً
echo "$HOME" # يطبع /home/alice
متغيرات البيئة
المتغيرات مثل $HOME و$USER و$PATH يحددها النظام. ويمكن تمرير متغيرك الخاص إلى العمليات الفرعية عبر export. أما إعدادات البيئة الدائمة فتُكتب في ~/.bashrc أو ~/.profile.
وسائط السكريبت
القيم التي تُمرَّر عند التشغيل متاحة في $1 و$2 وهكذا.
| المتغير | المحتوى |
|---|---|
$0 | اسم السكريبت |
$1، $2… | الوسيط الأول والثاني |
$# | عدد الوسائط |
"$@" | جميع الوسائط كل واحدة على حدة |
$? | رمز إنهاء آخر أمر |
$$ | معرّف العملية PID للسكريبت الحالي |
#!/bin/bash
echo "السكريبت $0 تلقّى $# وسيط(وسائط)"
echo "الأول: $1"
$ ./args.sh nginx 80
السكريبت ./args.sh تلقّى 2 وسيط(وسائط)
الأول: nginx
يُقرأ إدخال المستخدم بالأمر read: read -p "أدخل الاسم: " name.
الشرط if
يُعيد كل أمر رمز إنهاء: 0 للنجاح، وأي قيمة أخرى للخطأ. وتفحص العبارة if هذا الرمز تحديداً. وللمقارنات نستخدم عادةً [[ ... ]]، ولا بد من المسافات داخل الأقواس.
#!/bin/bash
if [[ $# -eq 0 ]]; then
echo "الاستخدام: $0 <مجلد>"
exit 1
fi
if [[ -d "$1" ]]; then
echo "المجلد $1 موجود"
elif [[ -f "$1" ]]; then
echo "$1 ملف، وليس مجلداً"
else
echo "$1 غير موجود"
fi
| الفحص | المعنى |
|---|---|
-f file | الملف العادي موجود |
-d dir | المجلد موجود |
-e path | المسار موجود |
-x file | الملف قابل للتنفيذ |
-z "$var" / -n "$var" | النص فارغ / غير فارغ |
"$a" == "$b"، != | مقارنة النصوص |
-eq -ne -lt -le -gt -ge | مقارنة الأرقام |
يمكن أيضاً فحص نتيجة أي أمر مباشرةً:
if systemctl is-active --quiet nginx; then
echo "nginx يعمل"
else
echo "nginx متوقف"
fi
وعند وجود خيارات كثيرة يكون case أنسب:
case "$1" in
start) echo "تشغيل" ;;
stop) echo "إيقاف" ;;
*) echo "أمر غير معروف: $1"; exit 1 ;;
esac
الحلقتان for وwhile
for: المرور على قائمة
for host in web1 web2 db1; do
echo "أفحص $host"
ping -c 1 -W 1 "$host" > /dev/null && echo " متاح" || echo " غير متاح"
done
for file in /var/log/*.log; do
echo "$file: $(wc -l < "$file") سطر"
done
for i in {1..5}; do
echo "المحاولة $i"
done
while: ما دام الشرط صحيحاً
المثال الكلاسيكي هو قراءة ملف سطراً بسطر:
while read -r user; do
echo "المستخدم: $user"
done < users.txt
وانتظار اكتمال تشغيل الخدمة:
count=0
until curl -sf http://localhost:8080/health > /dev/null; do
count=$((count + 1))
if [[ $count -ge 10 ]]; then
echo "لم تبدأ الخدمة"
exit 1
fi
sleep 3
done
echo "الخدمة جاهزة"
تُكتب العمليات الحسابية في bash بين قوسين مزدوجين: $((a + b)). وهي تعمل مع الأعداد الصحيحة فقط.
الدوال
يُنقل الكود المتكرر إلى دوال. وتستخدم الدالة الوسائط نفسها $1 و$2، ويمنع local المتغير من التسرب إلى خارج الدالة.
log() {
local level="$1"; shift
echo "$(date '+%F %T') [$level] $*"
}
log INFO "بدء النسخ الاحتياطي"
log ERROR "لا توجد مساحة كافية على القرص"
معالجة الأخطاء: set -euo pipefail
افتراضياً يواصل bash التنفيذ بعد فشل أمر، فقد ينتهي سكريبت النسخ الاحتياطي «بنجاح» دون أن ينسخ شيئاً. لذلك يُضاف في بداية السكريبتات وضع صارم:
#!/bin/bash
set -euo pipefail
-e: التوقف عند أول خطأ.-u: اعتبار الإشارة إلى متغير غير معرّف خطأً (يحمي من تنفيذrm -rf "$DIR/"عندما يكونDIRفارغاً).-o pipefail: يُعدّ الأنبوب فاشلاً إذا فشل أي جزء فيه.
للتصحيح شغّل السكريبت بالأمر bash -x script.sh، فيطبع bash كل أمر قبل تنفيذه. ولاكتشاف الأخطاء الشائعة قبل التشغيل تساعد أداة shellcheck.
مثال عملي: سكريبت نسخ احتياطي
#!/bin/bash
set -euo pipefail
SRC="${1:-/var/www}"
DST="/var/backups/site"
KEEP_DAYS=7
STAMP=$(date +%F_%H-%M)
mkdir -p "$DST"
tar -czf "$DST/site-$STAMP.tar.gz" -C "$(dirname "$SRC")" "$(basename "$SRC")"
echo "تم إنشاء الأرشيف $DST/site-$STAMP.tar.gz"
# حذف الأرشيفات الأقدم من KEEP_DAYS يوماً
find "$DST" -name "site-*.tar.gz" -mtime +"$KEEP_DAYS" -delete
تعني الصيغة ${1:-/var/www}: «استخدم الوسيط الأول، وإذا لم يوجد فاستخدم /var/www». احفظ السكريبت باسم /usr/local/bin/backup-site.sh واجعله قابلاً للتنفيذ: sudo chmod +x /usr/local/bin/backup-site.sh.
التشغيل المجدول: cron
cron خدمة تشغّل الأوامر وفق جدول زمني. تُحرَّر مهام المستخدم بالأمر crontab -e، وتُعرض بالأمر crontab -l، أما مهام root فتُحرَّر بالأمر sudo crontab -e.
يتكون سطر المهمة من خمسة حقول زمنية ثم الأمر:
# الدقيقة الساعة يوم_الشهر الشهر يوم_الأسبوع الأمر
30 2 * * * /usr/local/bin/backup-site.sh >> /var/log/backup.log 2>&1
| الجدول | وقت التشغيل |
|---|---|
*/5 * * * * | كل 5 دقائق |
0 * * * * | في بداية كل ساعة |
30 2 * * * | كل يوم الساعة 02:30 |
0 9 * * 1-5 | أيام العمل الساعة 09:00 |
0 3 1 * * | في اليوم الأول من كل شهر الساعة 03:00 |
@reboot | مرة واحدة بعد الإقلاع |
لماذا يعمل السكريبت يدوياً ولا يعمل في cron
- بيئة مختلفة.تعمل cron بالمتغير
PATHالمحدود، ولا تقرأ الملف~/.bashrc. استخدم المسارات الكاملة للأوامر والملفات، أو عرّفPATHفي بداية crontab. - مجلد عمل مختلف.تبدأ المهمة من المجلد الشخصي وليس من مكان السكريبت. استخدم المسارات المطلقة.
- علامة %.في crontab تعني
%سطراً جديداً، لذلك يجب كتابةdate +%Fداخل سطر المهمة على الشكل\%. والأسهل نقل الأمر إلى السكريبت. - ضياع المخرجات.وجّه المخرجات إلى سجل (
>> file 2>&1)، وإلا فلن ترى الأخطاء. وتظهر عمليات cron فيjournalctl -u cron(وفي أنظمة RHEL اسم الخدمةcrond).
في الأنظمة التي تستخدم systemd يمكن استخدام مؤقتات systemd بديلاً عن cron: فهي تكتب المخرجات في السجل، وتستطيع تعويض التشغيلات الفائتة.
الخلاصة
سكريبت Bash للمبتدئين هو ملف يبدأ بالسطر #!/bin/bash، ويحصل على صلاحية التشغيل، ويحتوي على سلسلة من الأوامر. ضع المتغيرات بين علامات اقتباس، وتحقق من الوسائط عبر if، واستخدم الحلقتين for وwhile، وفعّل الوضع الصارم set -euo pipefail، فتحصل على أداة أتمتة موثوقة يشغّلها cron وفق الجدول. وتُشرح سكريبتات bash والبيئة وcron عملياً في دورة لينكس.
الأسئلة الشائعة
ما الفرق بين bash وsh؟
sh هو الواجهة القياسية POSIX، وbash نسخة موسعة منها تضيف المصفوفات والأقواس المزدوجة ومزايا أخرى. السكريبت الذي يستخدم صيغ bash يجب أن يُشغَّل بـ bash، لا بـ sh.
ما امتداد ملف سكريبت bash؟
لا يهتم لينكس بالامتداد، فالمفسّر يُحدَّد بسطر shebang. الامتداد .sh مجرد عرف يسهّل معرفة أن الملف سكريبت.
كيف أمرر كلمة مرور إلى السكريبت بأمان؟
لا تمررها كوسيط، لأن الوسائط تظهر لباقي المستخدمين في الأمر ps. استخدم متغير بيئة من ملف صلاحيته 600، أو استخدم read -s للإدخال دون إظهار النص.
كيف أتحقق من أن السكريبت يعمل بصلاحيات root؟
قارن معرّف المستخدم بالصفر: if [[ $EUID -ne 0 ]]; then echo "يلزم root"; exit 1; fi.
كيف أشغّل السكريبت في الخلفية كي لا يتوقف بعد الخروج من SSH؟
استخدم nohup ./script.sh &، أو جلسة tmux أو screen، ولتشغيل دائم حوّل السكريبت إلى خدمة systemd.
يُشرح هذا الموضوع بالتفصيل مع التطبيق العملي في دورة «Linux: с нуля до уверенного администрирования».
- Bash-скрипты: от команды в терминале до рабочего скрипта автоматизации
- Пакеты, окружение и первая автоматизация: apt, профиль и cron