تخطَّ إلى المحتوى

سكربتات Shell في Linux: المتغيرات والشروط والحلقات

الدرس 10 من 10 · أساسيات Linux

في درس الصلاحيات كتبت أول سكربت: ملف فيه أوامر تُنفَّذ بالترتيب. لكن السكربت الحقيقي أذكى من قائمة أوامر: يستقبل مدخلات، ويتخذ قرارات، ويكرر العمل على عشرات الملفات. في هذا الدرس الأخير ستتعلم لغة Bash نفسها: المتغيرات والشروط والحلقات والدوال، وتجمعها في سكربت نسخ احتياطي تستخدمه فعلاً.

السكربت مثل وصفة طبخ تكتبها مرة واحدة: بعدها يكفي أن تقول «نفّذ الوصفة» بدل أن تتذكر الخطوات في كل مرة.

hello.sh
#!/bin/bash
name="Sara"
echo "Hello, $name!"
echo "You have ${#name} letters in your name."
echo 'Single quotes: $name'
نافذة طرفيّة
chmod +x hello.sh
./hello.sh
الناتج
Hello, Sara!
You have 4 letters in your name.
Single quotes: $name
  • السطر الأول #!/bin/bash يحدد المفسّر، و chmod +x يجعل الملف قابلاً للتنفيذ.
  • name="Sara": تعريف متغير. بلا مسافات حول علامة =.
  • $name: قراءة قيمته، و ${#name} عدد حروفه.
  • علامات التنصيص المزدوجة تستبدل المتغيرات بقيمها، والمفردة تبقي النص حرفياً.

الصيغة $(...) تشغّل أمراً وتضع ناتجه مكانها:

نافذة طرفيّة
files=$(ls .. | wc -l)
echo "count: $files"
الناتج
count: 10

والحسابات على الأعداد الصحيحة تُكتب داخل $((...)):

نافذة طرفيّة
x=5; y=3
echo $((x * y)) $((x / y)) $((x % y))
الناتج
15 1 2

القسمة هنا صحيحة: 5 على 3 تعطي 1، والباقي 2.

ما تكتبه بعد اسم السكربت يصله في متغيرات خاصة:

greet.sh
#!/bin/bash
echo "Script: $0"
echo "First: $1"
echo "Second: $2"
echo "Count: $#"
echo "All: $@"
نافذة طرفيّة
./greet.sh Omar Laila
الناتج
Script: ./greet.sh
First: Omar
Second: Laila
Count: 2
All: Omar Laila
المتغير المعنى
$1 و $2 … المعامل الأول والثاني وهكذا
$0 اسم السكربت نفسه
$# عدد المعاملات
$@ كل المعاملات معاً
$? رمز خروج آخر أمر

ولسؤال المستخدم أثناء التشغيل استخدم read: السطر read -p "What is your name? " name يطبع السؤال، وينتظر الإجابة، ويخزنها في المتغير name.

check.sh
#!/bin/bash
if [ $# -eq 0 ]; then
echo "Usage: $0 <file>"
exit 1
fi
if [ -f "$1" ]; then
lines=$(wc -l < "$1")
echo "$1 exists and has $lines lines"
elif [ -d "$1" ]; then
echo "$1 is a directory"
else
echo "$1 not found"
fi
نافذة طرفيّة
./check.sh
./check.sh ../scores.txt
./check.sh ../logs
./check.sh nothing.txt
الناتج
Usage: ./check.sh <file>
../scores.txt exists and has 6 lines
../logs is a directory
nothing.txt not found
  • الشرط يُكتب بين [ و ] مع مسافة إلزامية بعد الأول وقبل الثاني.
  • then تبدأ الجسم، و fi (كلمة if معكوسة) تنهيه.
  • exit 1: اخرج من السكربت برمز خطأ. تذكّر من درس العمليات: الصفر نجاح وغيره فشل.

أهم الفحوص:

الفحص يتحقق إذا
-f path المسار ملف موجود
-d path المسار مجلد موجود
-e path المسار موجود (أي نوع)
-z "$s" النص فارغ
"$a" = "$b" النصان متساويان، و != للاختلاف
$a -eq $b العددان متساويان، و -ne للاختلاف
-gt و -lt أكبر من، أصغر من
-ge و -le أكبر من أو يساوي، أصغر من أو يساوي

مقارنة الأرقام بالحروف (-gt) لا بالرموز (>)، لأن > في الطرفية تعني إعادة التوجيه إلى ملف!

grade.sh
#!/bin/bash
score=$1
if [ "$score" -ge 85 ]; then
echo "Excellent"
elif [ "$score" -ge 70 ]; then
echo "Good"
else
echo "Needs work"
fi

تشغيله بـ ./grade.sh 92 يطبع Excellent، وبـ 75 يطبع Good، وبـ 40 يطبع Needs work.

loops.sh
#!/bin/bash
for fruit in apple banana mango; do
echo "I like $fruit"
done
for i in {1..3}; do
echo "Round $i"
done
count=3
while [ $count -gt 0 ]; do
echo "Countdown: $count"
count=$((count - 1))
done
echo "Go!"
الناتج
I like apple
I like banana
I like mango
Round 1
Round 2
Round 3
Countdown: 3
Countdown: 2
Countdown: 1
Go!
  • for متغير in قائمة; do ... done: يكرر الجسم لكل عنصر في القائمة.
  • {1..3} تولّد الأرقام من 1 إلى 3.
  • while [ شرط ]; do ... done: يكرر ما دام الشرط متحققاً.

والاستخدام الأهم للحلقة for: المرور على ملفات، مع النجمة التي تعرفها:

count_lines.sh
#!/bin/bash
for file in ../logs/*.log ../scores.txt; do
lines=$(wc -l < "$file")
echo "$file: $lines"
done
الناتج
../logs/app.log: 8
../scores.txt: 6

هكذا تعالج مئة ملف بثلاثة أسطر: تغيير أسمائها، أو ضغطها، أو البحث فيها.

funcs.sh
#!/bin/bash
say_hello() {
echo "Hello, $1!"
}
add() {
echo $(($1 + $2))
}
say_hello "Mona"
say_hello "Ahmed"
result=$(add 7 5)
echo "7 + 5 = $result"
الناتج
Hello, Mona!
Hello, Ahmed!
7 + 5 = 12

الدالة تستقبل معاملاتها في $1 و $2 مثل السكربت تماماً، وتُستدعى باسمها بلا أقواس. ولأخذ نتيجتها تطبعها الدالة بـ echo وتلتقطها بـ $(...).

مثال متكامل: نسخ احتياطي

Section titled “مثال متكامل: نسخ احتياطي”
backup.sh
#!/bin/bash
# backup.sh: copy a folder into backups/ with today's date
source_dir=$1
backup_dir="backups"
stamp=$(date +%Y-%m-%d)
if [ ! -d "$source_dir" ]; then
echo "Error: $source_dir is not a directory"
exit 1
fi
mkdir -p "$backup_dir"
target="$backup_dir/$(basename "$source_dir")-$stamp"
cp -r "$source_dir" "$target"
files=$(find "$target" -type f | wc -l)
echo "Backed up $files files to $target"
نافذة طرفيّة
./backup.sh ../logs
./backup.sh ../nothing
الناتج
Backed up 2 files to backups/logs-2026-11-12
Error: ../nothing is not a directory

في خمسة عشر سطراً جمعنا كل ما تعلمته: معامل من المستخدم، وناتج أمر date في متغير، وفحص بـ if مع ! للنفي، ورمز خروج عند الخطأ، وأوامر mkdir و cp و find و wc من الدروس السابقة.

  1. اكتب سكربت info.sh يطبع اسم المستخدم (whoami)، والمجلد الحالي، وعدد الملفات فيه.
  2. اكتب سكربت even.sh يستقبل رقماً ويطبع هل هو زوجي أم فردي (تلميح: $(( $1 % 2 ))).
  3. اكتب سكربت يمر على كل ملفات .txt في المجلد الحالي ويطبع اسم كل ملف وعدد كلماته.
  4. تحدٍّ: عدّل backup.sh ليرفض العمل برسالة واضحة إذا لم يُعطَ أي معامل، وليطبع رسالة مختلفة إذا كانت النسخة موجودة مسبقاً.
  • مسافات حول =: name = Sara يعطي name: command not found، لأن Bash يظن name أمراً. اكتب name=Sara.
  • نسيان المسافات داخل الأقواس: [$a -eq 1] خطأ. الصحيح [ $a -eq 1 ].
  • متغير بلا علامات تنصيص: إذا كان $a فارغاً فإن [ $a = "x" ] يعطي unary operator expected. اكتب دائماً [ "$a" = "x" ]، وكذلك مع أسماء الملفات التي قد تحتوي مسافات.
  • نسيان chmod +x: يعطي Permission denied عند التشغيل بـ ./script.sh.

سؤال

شغّلت ./deploy.sh web 8080. ما قيمة $2 داخل السكربت؟

سؤال

أي شرط يفحص أن المتغير count أكبر من 10 في Bash؟

  • name=value بلا مسافات، و $name للقراءة، و $(command) لناتج أمر، و $((...)) للحساب.
  • $1 و $2 معاملات السكربت، و $# عددها، و $? رمز خروج آخر أمر.
  • if [ شرط ]; then ... fi مع -f و -d للملفات، و -eq و -gt للأرقام.
  • for x in قائمة; do ... done للتكرار على عناصر أو ملفات، و while ما دام الشرط متحققاً.
  • مبروك! أنهيت كورس Linux: من أول أمر إلى سكربتات تؤدي عملك عنك.