Bash for Oracle DBAs قسمت چهارم حلقه while و خواندن فایل‌ها در Bash

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

for زمانی مناسب است که لیست مشخصی از آیتم‌ها داشته باشیم، مثل:

  • فایل‌ها
  • اسکریپت‌ها
  • اعداد

اما در بسیاری از اسکریپت‌های مدیریتی لازم است داده‌ها را خط به خط پردازش کنیم.

اینجاست که حلقه while اهمیت پیدا می‌کند.

این حلقه یکی از مهم‌ترین ابزارها برای کارهایی مثل:

  • پردازش فایل‌ها
  • تحلیل logها
  • خواندن خروجی دستورات

است.


ساختار پایه while

ساختار کلی:

while conditions
do
commands
done

مثال ساده:

i=1

while [[ $i -le 5 ]]
do
  echo "Number: $i"
  ((i++))
done

در این مثال:

  • متغیر i از 1 شروع می‌شود
  • تا زمانی که شرط برقرار باشد حلقه اجرا می‌شود
  • در هر تکرار مقدار آن افزایش می‌یابد

مهم‌ترین کاربرد while: خواندن فایل خط به خط

یکی از الگوهای بسیار رایج در Bash:

while read line
do
  echo "$line"
done < file.txt

در اینجا:

  • فایل file.txt خط به خط خوانده می‌شود
  • هر خط در متغیر line قرار می‌گیرد
  • سپس دستورات داخل حلقه اجرا می‌شوند

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


مثال واقعی: بررسی کاربران سیستم

فایل /etc/passwd اطلاعات کاربران سیستم را نگه می‌دارد.

می‌توانیم آن را خط به خط بخوانیم:

while read line
do
  echo "User entry: $line"
done < /etc/passwd

اما معمولاً فقط بخشی از اطلاعات برای ما مهم است.

مثلاً نام کاربر.


استفاده از IFS برای جدا کردن فیلدها

در فایل /etc/passwd فیلدها با : جدا شده‌اند.

می‌توانیم هنگام خواندن فایل این جداکننده را مشخص کنیم:

while IFS=: read user x uid gid home shell
do
  echo "User: $user | UID: $uid | Shell: $shell"
done < /etc/passwd

در این مثال:

  • IFS=: تعیین می‌کند جداکننده : است
  • هر فیلد در یک متغیر قرار می‌گیرد

این تکنیک برای parsing فایل‌ها بسیار مهم است.


پردازش logها با while

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

while read line
do
  if [[ "$line" == *ERROR* ]]; then
    echo "Error found: $line"
  fi
done < /var/log/messages

در این مثال:

  • هر خط از log خوانده می‌شود
  • اگر کلمه ERROR وجود داشته باشد چاپ می‌شود

این نوع اسکریپت پایه بسیاری از System Health Check Scriptها است.


خواندن خروجی یک دستور

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

مثلاً بررسی فرآیندها:

ps -ef | while read line
do
  echo "$line"
done

در این حالت:

  • خروجی ps وارد حلقه می‌شود
  • هر خط جداگانه پردازش می‌شود

نکته مهم: استفاده از read -r

در اسکریپت‌های حرفه‌ای معمولاً از این فرم استفاده می‌شود:

while read -r line
do
  echo "$line"
done < file.txt

گزینه -r باعث می‌شود Bash کاراکترهای escape را تفسیر نکند و داده‌ها دقیق‌تر خوانده شوند.


مثال عملی

اسکریپتی که فایل‌های .conf را بررسی می‌کند:

ls /etc/*.conf 2>/dev/null | while read -r file
do
  if [[ ! -r "$file" ]]; then
    echo "File not readable: $file"
  fi
done

این اسکریپت:

  1. فایل‌های .conf را لیست می‌کند
  2. آن‌ها را خط به خط می‌خواند
  3. بررسی می‌کند کدام فایل قابل خواندن نیست

اشتباه رایج

❌ اشتباه:

cat file.txt | while read line

این کار غیرضروری است.

✅ بهتر:

while read line
do
  echo "$line"
done < file.txt

این روش ساده‌تر و کارآمدتر است.


تمرین

اسکریپتی بنویسید که:

  1. فایل /etc/passwd را بخواند
  2. فقط کاربرانی را چاپ کند که shell آن‌ها /bin/bash است