تا اینجا یاد گرفتیم:
- شرطها
- حلقهها
- توابع
- پردازش متن
اما هنوز یک مشکل بزرگ باقی مانده است.
بسیاری از اسکریپتهای Bash در محیط production بهدرستی خطاها را مدیریت نمیکنند.
در نتیجه ممکن است:
- بخشی از اسکریپت fail شود
- اما اسکریپت ادامه پیدا کند
- و نتیجه نهایی اشتباه باشد
برای جلوگیری از این مشکل باید Error Handling را جدی بگیریم.
مفهوم Exit Code در لینوکس
هر دستور در لینوکس یک کد خروج (Exit Status) برمیگرداند.
قاعده کلی:
0 → موفق
غیر صفر → خطا
مثال:
ls /etc/passwd
echo $?
اگر فایل وجود داشته باشد:
0
اگر وجود نداشته باشید:
2
متغیر $? همیشه exit code آخرین دستور را نگه میدارد.
استفاده از Exit Code در شرطها
مثال:
cp file1 file2
if [[ $? -ne 0 ]]; then
echo "Copy failed"
fi
اما این روش خیلی تمیز نیست.
روش بهتر این است که مستقیماً دستور را در if قرار دهیم.
✅ بهتر:
if cp file1 file2; then
echo "Copy successful"
else
echo "Copy failed"
fi
گزینه مهم: set -e
یکی از مهمترین تنظیمات برای اسکریپتها:
set -e
معنی آن:
اگر هر دستور خطا بدهد، اسکریپت فوراً متوقف میشود.
مثال:
set -e
cp file1 file2
rm file3
اگر cp شکست بخورد، دستور rm اجرا نمیشود.
این کار از بسیاری از خطاهای خطرناک جلوگیری میکند.
گزینه مهم: set -u
set -u
اگر از متغیر تعریفنشده استفاده شود، اسکریپت خطا میدهد.
مثال:
echo $username
اگر username تعریف نشده باشد، اسکریپت fail میشود.
این کار از باگهای پنهان جلوگیری میکند.
گزینه مهم: pipefail
در pipelineها مشکل رایجی وجود دارد.
مثال:
grep ERROR file.log | sort
اگر grep خطا بدهد اما sort موفق باشد، exit code برابر 0 میشود.
برای جلوگیری از این مشکل:
set -o pipefail
در این حالت اگر هر بخش pipeline خطا بدهد، اسکریپت fail میشود.
الگوی استاندارد حرفهای
در ابتدای اسکریپتهای حرفهای معمولاً این خط قرار میگیرد:
set -euo pipefail
معنی آن:
-eتوقف در صورت خطا-uخطا در صورت متغیر تعریفنشدهpipefailتشخیص خطای pipeline
این یکی از بهترین practiceها در Bash scripting است.
مدیریت خطا در توابع
میتوانیم در توابع هم خطاها را بررسی کنیم.
مثال:
check_file() {
local file=$1
if [[ ! -f "$file" ]]; then
echo "File not found: $file"
return 1
fi
echo "File exists"
}
استفاده:
if ! check_file "/etc/passwd"; then
exit 1
fi
مثال واقعی: بررسی backup
فرض کنید میخواهیم بررسی کنیم فایل backup وجود دارد یا نه.
#!/bin/bash
set -euo pipefail
backup="/backup/db.bkp"
if [[ ! -f "$backup" ]]; then
echo "Backup file not found"
exit 1
fi
echo "Backup file exists"
اگر backup وجود نداشته باشد اسکریپت با خطا خارج میشود.
ثبت خطا در log
در اسکریپتهای واقعی بهتر است خطاها log شوند.
مثال:
log() {
echo "[$(date)] $1"
}
if ! systemctl is-active --quiet sshd; then
log "sshd service is not running"
fi
اشتباه رایج
❌ نادیده گرفتن خطاها:
cp file1 file2
rm file3
اگر cp fail شود ممکن است rm فایل مهمی را حذف کند.
✅ بهتر:
set -euo pipefail
تمرین
- اسکریپتی بنویسید که بررسی کند یک دایرکتوری وجود دارد.
- اگر وجود نداشت پیام خطا چاپ کند و exit کند.
- اگر وجود داشت تعداد فایلها را چاپ کند.