Bash for Oracle DBAs قسمت پنجم توابع در Bash و ساخت اسکریپت‌های ماژولار

در قسمت قبل ما با حلقه while آشنا شدیم

تا اینجا اسکریپت‌های ما معمولاً به شکل خطی (linear) نوشته شده‌اند.

اما وقتی اسکریپت بزرگ‌تر می‌شود — مثلاً برای:

  • System Health Check
  • Hardening Check
  • Backup Monitoring

نوشتن همه چیز پشت سر هم باعث می‌شود اسکریپت:

  • خوانایی کمی داشته باشد
  • نگهداری آن سخت شود
  • نتوانیم بخش‌های مختلف را دوباره استفاده کنیم

راه حل این مشکل استفاده از توابع (Functions) در Bash است.


تابع در Bash چیست؟

تابع مجموعه‌ای از دستورات است که می‌توان آن را چندین بار فراخوانی کرد.

ساختار ساده:

function_name() {
    commands
}

مثال:

say_hello() {
  echo "Hello"
}

say_hello

مثال واقعی‌تر

فرض کنید در اسکریپت چند بار نیاز داریم تاریخ و زمان را چاپ کنیم.

بدون تابع:

echo "[$(date)] Starting script"
echo "[$(date)] Checking files"
echo "[$(date)] Script finished"

با تابع:

log_time() {
  echo "[$(date)] $1"
}

log_time "Starting script"
log_time "Checking files"
log_time "Script finished"

اینجا:

$1

پارامتر اول تابع است.


پارامترهای تابع

در Bash پارامترهای تابع دقیقاً مثل پارامترهای اسکریپت هستند.

$1
$2
$3

مثال:

check_file() {
  if [[ -f "$1" ]]; then
    echo "File exists: $1"
  else
    echo "File not found: $1"
  fi
}

check_file /etc/passwd

در اینجا:

$1 = /etc/passwd

مقدار بازگشتی تابع

در Bash توابع با دستور return یک کد وضعیت (exit status) برمی‌گردانند.

مثال:

check_file() {
  if [[ -f "$1" ]]; then
    return 0
  else
    return 1
  fi
}

check_file /etc/passwd

if [[ $? -eq 0 ]]; then
  echo "File exists"
else
  echo "File not found"
fi

در لینوکس:

0 = موفق
غیر صفر = خطا

استفاده از متغیر local

یکی از اشتباهات رایج در Bash استفاده از متغیرهای global است.

مثال مشکل‌دار:

check_user() {
  user=$1
  echo "Checking $user"
}

در این حالت متغیر user در کل اسکریپت قابل دسترسی است.

✅ روش بهتر:

check_user() {
  local user=$1
  echo "Checking $user"
}

متغیر local فقط داخل تابع قابل استفاده است.

این کار باعث می‌شود اسکریپت:

  • قابل پیش‌بینی‌تر
  • امن‌تر
  • قابل نگهداری‌تر

باشد.


مثال واقعی: Health Check Script

فرض کنید می‌خواهیم چند بررسی مختلف انجام دهیم.

می‌توانیم هر کدام را در یک تابع قرار دهیم.

check_disk() {
  echo "Checking disk usage..."
  df -h
}

check_memory() {
  echo "Checking memory..."
  free -m
}

check_uptime() {
  echo "Checking uptime..."
  uptime
}

check_disk
check_memory
check_uptime

این روش ساختار اسکریپت را بسیار مرتب‌تر می‌کند.


ترتیب تعریف توابع

در Bash باید توابع قبل از استفاده تعریف شوند.

✅ درست:

say_hello() {
  echo "Hello"
}

say_hello

❌ اشتباه:

say_hello

say_hello() {
  echo "Hello"
}

مثال کوچک واقعی برای DBA

اسکریپتی که وضعیت چند سرویس مهم را بررسی می‌کند:

check_service() {
  local service=$1

  if systemctl is-active --quiet "$service"; then
    echo "$service is running"
  else
    echo "$service is NOT running"
  fi
}

check_service sshd
check_service crond
check_service rsyslog

این الگو در بسیاری از اسکریپت‌های monitoring و automation استفاده می‌شود.


تمرین

یک تابع بنویسید که:

  1. یک مسیر به عنوان پارامتر بگیرد
  2. بررسی کند دایرکتوری وجود دارد یا نه
  3. اگر وجود داشت تعداد فایل‌های آن را چاپ کند

 

مثال: