کنترل جریان: ایجاد حلقه با while و until در اسکریپتنویسی
در درس قبلی یک برنامه منودار ایجاد کردیم تا اطلاعات سیستمی مختلف را ایجاد کند. برنامه کار کرد ولی هنوز مشکلات بزرگی در زمینه بکارگیری و قابلیت استفاده دارد. این برنامه فقط یک انتخاب را اجرا میکند و سپس به آن پایان میدهد. حتی بدتر از آن اگر که یک انتخاب اشتباه وارد شود برنامه با یک پیام خطا پایان مییابد. بدون اینکه حتی به کاربر این فرصت را بدهد که دوباره سعی کند. بهتر بود که برنامهای ایجاد کنیم که در نتیجه آن بتواند نمایش منو را تکرار کند و تا زمانی که کاربر خروج را انتخاب نکرده است از برنامه خارج نشود و انتخاب مجدد ممکن باشد.
در این درس نگاهی به مفهوم تکرار و ایجاد حلقه میکنیم که موجب میشود بخشهایی از برنامه تکرار شوند. شل (Shell) سه گزینه برای ایجاد حلقه به ما داده است که دو مورد از آنها یعنی While و Until را در این درس بررسی کرده و مورد آخر یعنی for را در دروس بعدی بررسی
خواهیم کرد.
ایجاد حلقه و تکرار (Looping)
زندگی روزمره ما پر از کارهای تکراری است. رفتن هر روزه به سر کار تهیه صبحانه و حتی برش زدن کاهو همگی وظایفی هستند که نیازمند تکرار و یکسری گامهای مشخص هستند. فرض کنید که میخواهید کاهو را برش دهید. این پروسه را به صورت زیر دنبال میکنیم:
- آوردن تخته برش
- آوردن چاقو
- جلو آوردن کاهو
- قرار دادن کاهو بر روی تخته برش
- بالا آوردن چاقو
- برش کاهو
- این کار را تکرار می کنیم
اگر کاهو برش خورد از حلقه خارج شو و برگرد به گام چهارم و برش بعدی را ایجاد کن… چی شد. بله حتی پروسه برش ساده کاهو را نیز میتوان درون یک حلقه جای داد گام های ۴ تا ۷ آنقدر تکرار میشوند تا کل کاهو قطعهقطعه شود.
حلقه while
بش (Bah) نیز میتواند ایده مشابه را بیان کنند. فرض کنید که میخواهید ۵ عدد را در یک توالی ترتیب ۱ تا ۵ نمایش دهید. یک اسکریپت بش را میتوان به صورت زیر ایجاد کرد:
#!/bin/bash
# while-count: display a series of numbers
count=1
while [ $count -le 5 ]; do
echo $count
count=$((count + 1))
done
echo "Finished."
وقتی که این اسکریپت اجرا شود به صورت زیر نمایش داده میشود:
[me@linuxbox ~]$ while-count 1 2 3 4 5 Finished.
ساختار دستوری whale نیز به صورت زیر است:
while commands; do commands; done
شبیه if عبارت while نیز وضعیت خروج یک لیست از فرمانها را ارزیابی میکند. تا زمانی که وضعیت خروج صفر است. فرمانها درون حلقه اجرا میشود. درون اسکریپت بالا متغیر count قبل از حلقه ایجاد و مقداردهی میشود مقدار اولیه ۱ است. سپس حلقه while وضعیت خروج را ارزیابی کرده و مقدار صفر را بازمیگرداند و دستورات درون حلقه اجرا میشود و
هر بار یک مقدار به مقدار count افزوده میشود پس از ٦ تکرار حلقه مقدار count به مقدار ٦ رسیده و دیگر فرمان تست وضعیت خروج صفر را بر نمیگرداند چونکه این بار $count کوچکتر از ۵ نیست بلکه ۶ هست. در نتیجه حلقه شکسته میشود و ادامه برنامه پس از loop اجرا میشود. ما میتوانیم از یک حلقه while کمک بگیریم تا برنامه read menu را که در درس قبل ایجاد کردیم را توسعه دهیم. درست به صورت زیر:
#!/bin/bash
# while-menu: a menu driven system information program
DELAY=3 # Number of seconds to display results
while [[ $REPLY != 0 ]]; do
clear
cat <<- _EOF_
Please Select:
1. Display System Information
2. Display Disk Space
3. Display Home Space Utilization
0. Quit
_EOF_
read -p "Enter selection [0-3] > "
if [[ $REPLY =~ ^[0-3]$ ]]; then
if [[ $REPLY == 1 ]]; then
echo "Hostname: $HOSTNAME"
uptime
sleep $DELAY
fi
if [[ $REPLY == 2 ]]; then
df -h
sleep $DELAY
fi
if [[ $REPLY == 3 ]]; then
if [[ $(id -u) -eq 0 ]]; then
echo "Home Space Utilization (All Users)"
du -sh /home/*
else
echo "Home Space Utilization ($USER)"
du -sh $HOME
fi
sleep $DELAY
fi
else
echo "Invalid entry."
sleep $DELAY
fi
done
echo "Program terminated."
با محصور کردن این منو درون حلقه loop قادر هستیم تا برنامه نمایش منو را پس از هر انتخاب تکرار کنیم . loop ادامه پیدا میکند تا زمانیکه REPLAY برابر صفر نباشد و منو دوباره نمایش داده میشود و این باعث میشود که این فرصت به کاربر داده شود تا یک بار دیگر منو را انتخاب کند. در پایان هر حرکت یک فرمان sleep اجرا میشود که باعث میشود برنامه برای چند ثانیه متوقف شود تا اجازه دهد نتایج انتخاب قبل از پاک شدن از روی صفحه نمایش دیده شود و سپس مجدد منو نمایش داده شود.
شکستن و خارج شدن از یک حلقه
بش (bash) دو فرمان درونساخت را فراهم میکنند که میتوان از آنها برای کنترل جریان برنامه درون حلقه استفاده کرد. دستور break بلافاصله یک loop را میشکند و کنترل برنامه به عبارت بعدی پس از حلقه بازمیگردد. فرمان continue موجب میشود که باقیمانده حلقه رد شود و کنترل برنامه به تکرار بعدی حلقه بازگردد. در اینجا یک نسخه از برنامه while menu را میبینیم که فرمانهای break و continue در آن به کار رفتهاند.
#!/bin/bash
# while-menu2: a menu driven system information program
DELAY=3 # Number of seconds to display results
while true; do
clear
cat <<- _EOF_
Please Select:
1. Display System Information
2. Display Disk Space
3. Display Home Space Utilization
0. Quit
_EOF_
read -p "Enter selection [0-3] > "
if [[ $REPLY =~ ^[0-3]$ ]]; then
if [[ $REPLY == 1 ]]; then
echo "Hostname: $HOSTNAME"
uptime
sleep $DELAY
continue
fi
if [[ $REPLY == 2 ]]; then
df -h
sleep $DELAY
continue
fi
if [[ $REPLY == 3 ]]; then
if [[ $(id -u) -eq 0 ]]; then
echo "Home Space Utilization (All Users)"
du -sh /home/*
else
echo "Home Space Utilization ($USER)"
du -sh $HOME
fi
sleep $DELAY
continue
fi
if [[ $REPLY == 0 ]]; then
break
fi
else
echo "Invalid entry."
sleep $DELAY
fi
done
echo "Program terminated."
در این نسخه از اسکریپت ما یک حلقه بیپایان ایجاد کردهایم حلقهای که هیچوقت با اتکا به خودش پایان نمییابد با استفاده از دستور true که وضعیت خروج را برای while تامین میکند.
از آنجایی که true همیشه وضعیت خروج صفر را ایجاد میکند. حلقه نیز هرگز پایان نمیپذیرد . این یک تکنیک اسکریپتنویسی رایج است. از آنجایی که حلقه با اتکا به خود پایان نمیپذیرد. این به برنامهنویس بستگی دارد تا راهی را برای شکستن حلقه در زمان صحیح فراهم کند.
در این اسکریپت فرمان break زمانی به منظور خروج از حلقه استفاده میشود که انتخاب صفر باشد. فرمان continue در پایان دیگر انتخابهای اسکریپت قرار داده شده است تا اجرای بهتر را ممکن سازد.
با استفاده از continue اسکربیت زمانی که یک انتخاب شناسایی میشود از کدی که به آن نیازی نیست عبور میکند. برای مثال اگر انتخاب ۱ انتخاب شده و شناسایی شده باشد. دیگر دلیلی برای تست برای دیگر انتخابها نیست.
حلقه Until (تا زمانیکه)
فرمان until بسیار شبیه while میباشد. به جز اینکه until زمانیکه با وضعیت خروج غیر صفر مواجه شد به جای خروج از یک حلقه درست برعکس عمل میکند. یک حلقه until ادامه پیدا میکند تا زمانیکه وضعیت خروج صفر را دریافت کند و زمانیکه وضعیت خروج صفر را دریافت کرد از حلقه خارج میشود. در اسکریپت while count ما حلقه را ادامه میدادیم تا زمانیکه مقدار متغیر count کمتر یا برابر باشد. میتوانیم همین نتیجه را با استفاده از حلقه until در اسکریپت زیر بدست آوریم:
#!/bin/bash
# until-count: display a series of numbers
count=1
until [ $count -gt 5 ]; do
echo $count
count=$((count + 1))
done
echo "Finished."
با تغییر عبارت تست به $count -gt حلقه until در زمان صحیح خارج خواهد شد.
تصمیم به استفاده از while یا until بستگی به این دارد که کدام یک میتواند واضح ترین ساختار تست را برای شما ایجاد کند.
خواندن فایلها با حلقهها
while و until می توانند ورودی استاندارد را پردازش کنند. این ویژگی به فایلها اجازه میدهد تا با حلقههای while و until پردازش شوند. در مثال زیر ما محتویات فایل distros.txt را که در درسهای اولیه ایجاد کردهایم نشان میدهیم:
#!/bin/bash
# while-read: read lines from a file
while read distro version release; do
printf "Distro: %s\tVersion: %s\tReleased: %s\n" \
$distro \
$version \
$release
done < distros.txt
به منظور هدایت یک فایل به حلقه عملگر هدایت را پس از عبارت done قرار میدهیم. حلقه از read برای وارد کردن فیلدها از یک فایل هدایت شده استفاده میکند. فرمان read پس از خواندن هر خط با وضعیت خروج صفر خارج میشود تا به آخر قابل برسد. در این نقطه با یک وضعیت خروج غیر صفر خارج شده در نتیجه حلقه شکسته می شود.
همچنین میتوانیم ورودی استاندارد را به درون یک حلقه پایپ کنیم:
#!/bin/bash
# while-read2: read lines from a file
sort -k 1,1 -k 2n distros.txt | while read distro version release; do
printf "Distro: %s\tVersion: %s\tReleased: %s\n" \
$distro \
$version \
$release
done
در اینجا خروجی فرمان sort را گرفته و جریان متن را نمایش میدهیم. هر چند این نکته مهم است که به خاطر داشته باشیم از آنجاییکه حلقه را پایپ کردهایم، متغیرهای ایجاد شده و اختصاص یافته درون حلقه پس از پایان حلقه از بین خواهند رفت.
درباره فرشید نوتاش حقیقت
همیشه نیازمند یک منبع آموزشی فارسی در حوزه نرمافزارهای آزاد/ متنباز و سیستمعامل گنو/لینوکس بودم. از این رو این رسالت رو برای خودم تعریف کردم تا رسانه «محتوای باز» رو بوجود بیارم.
نوشتههای بیشتر از فرشید نوتاش حقیقتاین سایت از اکیسمت برای کاهش جفنگ استفاده میکند. درباره چگونگی پردازش دادههای دیدگاه خود بیشتر بدانید.
دیدگاهتان را بنویسید