Bash for Oracle DBAs Part 5: Loops and List Processing in Bash

Bash برای Oracle DBAها — بخش ۵: حلقه‌ها و پردازش لیست‌ها در Bash

در اسکریپت‌های Oracle DBA، به‌ویژه در Audit، Hardening، Migration و Remediation، خیلی وقت‌ها لازم است روی مجموعه‌ای از آیتم‌ها کار کنیم: فایل‌ها، instanceها، serviceها، tablespaceها، کاربران، مسیرها یا خطوط خروجی commandها. در چنین سناریوهایی، حلقه‌ها و پردازش لیست‌ها در Bash اهمیت زیادی پیدا می‌کنند.

در این مقاله با ساختارهای مهمی مانند for، while، until، خواندن line-by-line، پردازش خروجی commandها، و تفاوت‌های مهم بین word splitting و quoting آشنا می‌شویم.

۱) چرا حلقه‌ها مهم هستند؟

بسیاری از اسکریپت‌های Oracle DBA فقط یک command را اجرا نمی‌کنند؛ بلکه باید روی چندین مورد تکرار شوند. برای مثال:

  • بررسی چندین فایل configuration؛
  • اعمال یک policy روی چند مسیر؛
  • پردازش خروجی ps، df، ls یا sqlplus؛
  • اجرای عملیات روی چند database user یا چند host؛
  • بررسی چندین row از یک report یا log.

بدون حلقه‌ها، مجبور می‌شوید یک command را بارها تکرار کنید که هم خطاپذیر است و هم نگهداری آن سخت می‌شود.

۲) حلقه for

ساده‌ترین نوع حلقه در Bash، حلقه for است. این حلقه روی یک لیست از آیتم‌ها حرکت می‌کند:

for item in alpha beta gamma; do
    echo "Processing: $item"
done

این الگو برای زمانی که از قبل آیتم‌های مشخص دارید بسیار مناسب است. در اسکریپت‌های DBA، این آیتم‌ها می‌توانند نام چند فایل یا چند service باشند:

for cfg in /etc/ssh/sshd_config /etc/hosts /etc/resolv.conf; do
    if [[ -f "$cfg" ]]; then
        echo "Found: $cfg"
    fi
done

توجه کنید که مسیرها همیشه باید داخل کوتیشن باشند تا اگر فاصله یا کاراکتر خاصی داشتند، به درستی پردازش شوند.

۳) حلقه for روی خروجی command

یکی از کاربردهای رایج، گرفتن خروجی یک command و پردازش آن است. اما باید مراقب word splitting باشید:

for file in $(ls /etc/ssh/*.conf 2>/dev/null); do
    echo "File: $file"
done

این روش در بسیاری از مواقع ایده‌آل نیست، چون خروجی command بر اساس whitespace جدا می‌شود و اگر نام فایل فاصله داشته باشد، مشکل ایجاد می‌کند. در اسکریپت‌های حرفه‌ای بهتر است از glob یا while-read استفاده شود.

روش بهتر:

for file in /etc/ssh/*.conf; do
    [[ -e "$file" ]] || continue
    echo "File: $file"
done

۴) حلقه while

حلقه while تا زمانی که یک شرط درست باشد اجرا می‌شود:

count=1
while [[ $count -le 5 ]]; do
    echo "Count: $count"
    ((count++))
done

در اسکریپت‌های DBA، while برای خواندن line-by-line بسیار پرکاربرد است.

۵) خواندن فایل line by line

یکی از مهم‌ترین الگوها در Bash این است که فایل یا خروجی را خط‌به‌خط بخوانیم:

while IFS= read -r line; do
    echo "Line: $line"
done < /etc/hosts

در این الگو:

  • IFS= از حذف یا تغییر ناخواسته فاصله‌های ابتدا/انتهای خط جلوگیری می‌کند؛
  • -r باعث می‌شود backslashها به‌صورت literal خوانده شوند.

این ساختار برای پردازش reportها، audit logها و خروجی‌های متنی Oracle بسیار مهم است.

۶) خواندن خروجی command با while read

گاهی لازم است خروجی یک command را به صورت امن پردازش کنیم. به‌جای استفاده از for روی command substitution، از pipe یا redirection استفاده کنید:

df -h | while IFS= read -r line; do
    echo "$line"
done

اگر می‌خواهید خروجی بعداً در همان shell اصلی استفاده شود، توجه کنید که در بعضی shellها، pipe یک subshell ایجاد می‌کند. در این موارد، redirection مستقیم یا process substitution می‌تواند بهتر باشد.

while IFS= read -r line; do
    echo "$line"
done < <(df -h)

۷) حلقه until

حلقه until برعکس while عمل می‌کند؛ تا زمانی که شرط false باشد اجرا می‌شود:

count=1
until [[ $count -gt 5 ]]; do
    echo "Count: $count"
    ((count++))
done

این ساختار در retry logic بسیار مفید است؛ مثلاً تلاش مجدد برای اتصال به دیتابیس تا زمانی که موفق شود یا تعداد تلاش‌ها تمام شود.

۸) break و continue

برای کنترل بهتر جریان حلقه از break و continue استفاده می‌کنیم:

for file in /etc/ssh/*.conf; do
    [[ -f "$file" ]] || continue
    if [[ "$file" == *"backup"* ]]; then
        break
    fi
    echo "Processing $file"
done

continue به iteration بعدی می‌رود و break حلقه را متوقف می‌کند.

۹) پردازش لیست‌ها با آرایه‌ها

آرایه‌ها برای ذخیره چند مقدار بسیار مناسب‌اند و خوانایی اسکریپت را بالا می‌برند:

files=(
  "/etc/ssh/sshd_config"
  "/etc/hosts"
  "/etc/resolv.conf"
)

for file in "${files[@]}"; do
    echo "Checking $file"
done

با استفاده از "${files[@]}" هر عنصر آرایه به صورت جداگانه و بدون شکستن بر اساس whitespace پردازش می‌شود.

۱۰) پردازش خروجی دستورها به صورت امن

در اسکریپت‌های Oracle، ممکن است خروجی ps، ls یا sqlplus را پردازش کنید. همیشه سعی کنید تا حد امکان از ابزارهایی استفاده کنید که خروجی قابل‌پیش‌بینی‌تری دارند:

while IFS= read -r dbline; do
    echo "DB output: $dbline"
done < <(sqlplus -s / as sysdba <<'EOF'
set heading off feedback off pages 0
select name from v$database;
exit
EOF
)

این روش در اسکریپت‌های DBA برای جمع‌آوری اطلاعات از دیتابیس بسیار کاربردی است. در مقالات بعدی درباره command substitution و here-doc بیشتر صحبت می‌کنیم.

۱۱) استفاده از read با delimiter سفارشی

گاهی داده‌ها با جداکننده‌ای غیر از فاصله یا newline ذخیره شده‌اند. در این موارد می‌توان IFS را تغییر داد:

oldIFS=$IFS
IFS=:
while IFS=: read -r user shell; do
    echo "User: $user, Shell: $shell"
done < /etc/passwd
IFS=$oldIFS

برای جلوگیری از اثر جانبی، بهتر است IFS را فقط در همان scope مورد نیاز تغییر دهید یا مقدار قبلی را بازگردانید.

۱۲) نمونه کاربردی برای Oracle DBA

مثال زیر چند فایل مهم را بررسی می‌کند و فقط فایل‌های موجود را پردازش می‌کند:

#!/bin/bash

configs=(
  "/etc/ssh/sshd_config"
  "/etc/hosts"
  "/etc/resolv.conf"
)

for cfg in "${configs[@]}"; do
    if [[ -f "$cfg" && -r "$cfg" ]]; then
        echo "OK: $cfg"
    else
        echo "WARN: $cfg is missing or unreadable"
    fi
done

این الگو برای health check و audit check بسیار رایج است.

۱۳) خطاهای رایج

برخی خطاهای متداول در حلقه‌ها عبارت‌اند از:

# Incorrect: word splitting may break paths
for file in $(ls /etc/*.conf); do
    echo "$file"
done

# Better: use glob
for file in /etc/*.conf; do
    [[ -e "$file" ]] || continue
    echo "$file"
done

همچنین در خواندن فایل، استفاده نکردن از -r می‌تواند backslashها را خراب کند:

# Better
while IFS= read -r line; do
    echo "$line"
done < input.txt

۱۴) جمع‌بندی

حلقه‌ها و پردازش لیست‌ها از مهم‌ترین مهارت‌های Bash برای Oracle DBAها هستند. با استفاده درست از for، while، until، read، آرایه‌ها و کنترل جریان، می‌توان اسکریپت‌هایی ساخت که هم خوانا باشند و هم برای عملیات Audit، Hardening و Remediation مناسب.

در مقاله بعدی وارد مبحث command substitution و here strings / here documents می‌شویم؛ ابزارهایی که برای گرفتن و تزریق خروجی commandها در اسکریپت‌های DBA بسیار مهم‌اند.


مقاله قبلی: Bash برای Oracle DBAها — بخش ۴: Exit Status و مدیریت خطا در Bash

مقاله بعدی: Bash برای Oracle DBAها — بخش ۶: Command Substitution و Here Docs در Bash