فصل یازدهم - حلقه‌ها

از Linuxreview Wiki
پرش به: ناوبری, جستجو


در این فصل شما نحوه‌ی تعریف و بکارگیری حلقه‌ها در شل را خواهید آموخت. حلقه‌ها به شما اجازه میدهند تا یک تکه کد را به تعداد دفعات دلخواه اجرا کنید. دو نوع کلی از حلقه‌هایی که در این فصل بررسی میشوند حلقه‌های زیر هستند:

  1. حلقه‌ for
  2. حلقه while

حلقه‌ی while این امکان را به شما میدهد تا مجوعه‌ای از‌ دستورات را تا زمانی که شرط حلقه برقرار است اجرا کنید.
و حلقه‌ی for امکان اجرای دستورات را برای هر آیتم از لیست مورد نظر فراهم میسازد.
همچنین در این فصل علاوه بر این دو حلقه، با دو حلقه‌ی دیگر به نام until و select نیز آشنا خواهید شد.


محتویات

[نهفتن]

حلقه‌ی while

از این ساختار برای ایجاد حلقه های تکرار استفاده می شود. تا زمانیکه دستور command عبارتی معتبر باشد مجموعه دستورات list اجرا خواهند شد و به محض نادرستی شرط، کنترل دستورات از حلقه خارج خواهد شد.
ساختار کلی این حقله به صورت زیر است:

while command ; do
	list
done

یا:

while command
do
	list
done

اگر هر دو دستور command و list دستورات کوتاه باشند به صورت زیر نیز میتوان حلقه را پیاده سازی کرد:

while command ; do list ; done


در اینجا command یک دستور اجرایی است، در حالی که list میتواند یک یا چند دستور باشد، به مجموعه دستورات list بدنه‌ی حلقه نیز گفته میشود. اگرچه command میتواند هر دستور معتبری در شل باشد ولی اغلب برای command از یک عبارت test استفاده میشود.
روند اجرای حلقه while در شل به صورت زیر است:

در واقع شرط ادامه یافتن حلقه while بازگشت مقداری غیر صفر پس از اجرای دستور command است به این معنی که دستور command با موفقیت انجام نشده است.


مثال: حلقه‌ی زیر را در نظر بگیرید:

x=0
while [ $x -lt 10 ] ; do
    echo $x
    x=$[x+1]
done

خروجی این حلقه به صورت زیر است:

0
1
2
3
4
5
6
7
8
9

هر بار که حلقه اجرا میشود، مقدار متغیر x با مقدار 10 مقایسه میشود، در صورتی از ۱۰ کوچکتر باشد، بدنه‌ی حلقه اجرا میشود. در بدنهٔ حلقه x چاپ شده و سپس یک واحد به آن اضافه می‌شود. به محض اینکه مقدار x بزرگتر یا برابر با ۱۰ شود اجرای حلقه خاتمه می‌یابد.


حلقه‌های تودرتو

در شل امکان استفاده از یک حلقه در داخل حلقه دیگر نیز امکان پذیر است:

while command1 ; do # this is loop1, the outer loop
	list1
	while command2 ; do # this is loop2, the inner loop
		list2
	done
	list3
done

در اینجا به حلقه‌ی loop1، حلقه‌ی اصلی یا حلقه‌ی خارجی و به حلقه‌ی loop2 حلقه‌ی داخلی گفته میشود.
شل در تعداد حلقه‌هایی که میخواهند به صورت تودرتو استفاده شوند، هیچ محدودیتی اعمال نمیکند و شما میتوانید از هر تعداد حلقه را به صورت تودرتو مورد استفاده قرار دهید.
مثال:

x=0
while [ "$x" -lt 10 ] ; do # this is loop1
	y="$x"
	while [ "$y" -ge 0 ] ; do # this is loop2
		echo -e "$y \c"
		y=$[y-1]
	done
	echo
	x=$[x+1]
done

خروجی این برنامه به صورت زیر است:

0 
1 0 
2 1 0 
3 2 1 0 
4 3 2 1 0 
5 4 3 2 1 0 
6 5 4 3 2 1 0 
7 6 5 4 3 2 1 0 
8 7 6 5 4 3 2 1 0 
9 8 7 6 5 4 3 2 1 0

کاربرد حلقه while برای تایید یک ورودی معتبر از کاربر

معمولا برای تعیین یک ورودی معتبر و تایید آن مراحل زیر طی میشود:


بهترین ابزار برای شبیه سازی این کاربرد حلقه‌ی while است. برای پیاده سازی مراحل بالا با حلقه while میتوان از الگوریتم زیر استفاده نمود:

مثال: مراحل بالا میتوانند به صورت زیر پیاده سازی شوند:

while read -p "Enter the name of a directory where your files are located: " RESPONSE ; do
    if [ -d "$RESPONSE" ] ; then
        break
    else
        echo "ERROR: Please enter a directory pathname."
    fi
done


اشاره: دستور read که در این مثال برای خواندن از ورودی به کارگرفته شده است در فصل ۱۳ بررسی شده‌است.


حلقه until

ساختار این حلقه دقیقا مشابه حلقه while و به صورت زیر است:

until command ; do
	list
done

یا

until command
do
	list
done


تنها تفاوت این حلقه با حلقه while شرط اتمام آن است. شرط پایان یافتن حلقه‌ی until اجرای موفقیت آمیز دستور command و برگشت کد صفر توسط آن است.


مثال: حلقه‌ی while زیر را در نظر بگیرید:

x=1
while [ ! $x -ge 10 ] ; do
	echo $x
	x=$[x+1]
done

که با استفاده از حلقه‌ی until میتوان آن‌را به صورت زیر پیاده سازی کرد:

x=1
until [ $x -ge 10 ] ; do
	echo $x
	x=$[x+1]
done

حلقه‌ی until هیچ مزیت خاصی نسبت به حلقه‌ی while ندارد و معمولا در بین برنامه نویس‌ها معمولا محبوب نیست و به همین دلیل از آن استفاده‌ی چندانی نمیکنند.

حلقه‌ی for

برخلاف حلقه‌ی while که تنها در یک شرایط خاص از حلقه خارج میشد، حلقه‌ی for برای پیمایش لیستی از آیتم‌ها مورد استفاده قرار میگیرد.
ساختار کلی حلقه‌ی for به صورت زیر است:

for name in word1 word2 ... wordN ; do
	list
done

یا

for name in word1 word2 ... wordN
do
	list
done

و شکل کوتاه شده‌ی آن به صورت زیر است:

for name in word1 word2 ... wordN ; do list ; done

در اینجا name متغیر و word1 تا wordN آیتم‌هایی هستند که با فاصله از هم جدا میشوند. در هر بار اجرای حلقه‌ی for متغیر name برابر با یکی از word1 تا wordN میشود. به صورتی که در اجرای اول برابر word1 در اجرای دوم برابر word2 و در اجرای آخر برابر wordN میشود. در واقع تعداد دفعاتی که بدنه‌ی حلقه‌ی for اجرا میشود برابر تعداد کلمات است.
مثال:

for i in 0 1 2 3 4 5 6 7 8 9 ; do
	echo $i
done

یا

for i in {0..9} ; do
	echo $i
done

یا

for i in `seq 0 9` ; do
	echo $i
done

یا

for ((i=0;i<=9;i++)) ; do
    echo $i
done


که همه منجر به تولید خروجی زیر میشود:

0
1
2
3
4
5
6
7
8
9

توجه کنید که هیچ به اجباری به پشت سر بودن اعداد یا کلمات با ترتیب خاص نیست.
مثال:

for i in 0 1 2 4 3 5 8 7 9 ; do
	echo $i
done

که منجر به تولید خروجی زیر میشود:

0
1
2
4
3
5
8
7
9

استفاده از حلقه‌ی for برای دستکاری چندین فایل

فرض کنید میخواهید چندین فایل را در یک دایرکتوری کپی و مجوز دسترسی آنها را تغییر دهید. در اینصورت باید شما به صورت دستی هر فایل را کپی و سطح دسترسی آنرا تغییر دهید. راه حل بهتر از حلقه‌ی for برای این منظور است. برای پیاده سازی این عمل با حلقه‌ی for روند زیر را باید طی کنیم:

مثال:

for FILE in $HOME/.bash* ; do
	cp $FILE ${HOME}/public_html
	chmod a+r ${HOME}/public_html/${FILE}
done

در این مثال تمام فایل‌هایی که در دایرکتوری خانه قرار دارند و اسم آنها با bash. شروع میشود، در دایرکتوری public_html موجود در دایرکتوری خانه کپی شده و مجوز خواندن برای همه گروه‌ها به آنها داده میشود.

حلقه‌ی select

یک راه ساده برای ایجاد منوی شماره گذاری شده که کاربر میتواند از بین گزینه‌های موجود انتخاب کند استفاده از حلقه‌ی select است. استفاده از این حلقه زمانی مفید است که شما نیاز دارید تا از کاربر سوالی پرسیده شود و کاربر از بین یک یا چند گزینه که شما مشخص کرده‌اید انتخاب کند.
شکل کلی حلقه‌ی select مشابه حلقه‌ی for و به صورت زیر میباشد:

select NAME in word1 word2 ... wordN ; do
	list
done

در اینجا NAME متغیر حلقه و word1 تا wordN دنباله‌ای از کلمات است که بوسیله‌ی فاصله از هم جدا میشوند.


روند کلی اجرای حلقه‌ی select به صورت زیر است:


مثال

select COMPONENT in comp1 comp2 comp3 all none ; do
	case $COMPONENT in
		comp1|comp2|comp3) CompConf $COMPONENT ;;
		all) CompConf comp1
		CompConf comp2
		CompConf comp3
		;;
		none) break ;;
		*) echo "ERROR: Invalid selection, $REPLY." ;;
 	esac
done

خروجی این برنامه به صورت زیر است:

1) comp1
2) comp2
3) comp3
4) all
5) none
#? 

علامت ?# به این معنی است که شل منتظر دریافت یک ورودی از کاربر است. که با توجه به هر عددی که کاربر وارد کند عمل خاصی طبق کد بالا انجام میشود.

نکته: با استفاده از متغیر PS3 میتوان در این حالت شکل prompt را در هنگام دریافت ورودی از حالت ?# به هر حالت دلخواه دیگر تغییر داد.


میتوان در مثال قبل کد زیر را به ابتدای برنامه اضافه کرد:

$ export PS3="Please make a selection => "

در این صورت پس از اجرای برنامه خروجی زیر حاصل میشود:

1) comp1
2) comp2
3) comp3
4) all
5) none
Please make a selection =>

کنترل حلقه‌ها

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


دستور break

این دستور برای پایان دادن به یک حلقه بدون در نظر گرفتن شرط حلقه استفاده میشود.‍ در واقع هر جا از دستور break استفاده شود، کنترل برنامه به خارج حلقه منتقل میشود.
مثال: حلقه‌ی نامتناهی زیر را نظر بگیرید:

while :
do
	read CMD
	case $CMD in
		[qQ]|[qQ][uU][iI][tT]) break ;;
		*) process $CMD ;;
	esac
done

در این مثال به دلیل اینکه شرط حلقه همیشه صحیح است، یک حلقه نامتناهی است و به طور معمول کنترل برنامه هیچگاه از حلقه خارج نمیشود. در این حلقه تنها زمانی از حلقه خارج میشود که ورودی کاربر یکی از کاراکترهای q,Q یا کلمه‌ی quit (بدون درنظر گرفتن بزرگی یا کوچکی حروف) باشد، در اینصورت دستور break اجرا شده و از حلقه خارج میشود.

همچنین برای دستور break میتوان یک عدد صحیح و مثبت بزرگتر از یک را به عنوان آگومان مشخص کرد. این آرگومان مشخص کننده‌ی سطح پرش از حلقه‌ها تودرتو است. به عبارت دیگر اگر چندین حلقه به صورت تودرتو داشته باشیم این آرگومان مشخص میکند که چند سطح به طرف بیرونی ترین حلقه پرش کنیم.
مثال: اسکریپت زیر را که برای تهیه پشتیبان میتواند مورد استفاده قرار بگیرد را در نظر بگیرید:

for i in 1 2 3 4 5 ; do
	mkdir -p /mnt/backup/docs/ch0${i}
	if [ $? -eq 0 ] ; then
		for j in doc c h m pl sh
		do
			cp $HOME/docs/ch0${i}/*.${j} /mnt/backup/docs/ch0${i}
			if [ $? -ne 0 ] ; then break 2 ; fi
		done
	else
			echo "Could not make backup directory."
fi
done

چون در این برنامه دو حلقه تودرتو داریم و آرگومان دستور break نیز برابر ۲ است، اجرای دستور break 2 موجب منتقل شدن کنترل برنامه به خارج از هر دو حلقه میشود.

دستور continue

این دستور مشابه دستور break است با این تفاوت که به جای خروج از کل حلقه تنها از یکبار اجرای حلقه جلوگیری میکند. استفاده از این دستور زمانی میتواند مفید باشد که در هنگام اجرای حلقه مشکلی پیش آمده ولی قصد خروج از کل حلقه را نداریم و تنها نیاز داریم تا از یکبار اجرای حلقه پرش کنیم.
مثال

for FILE in $FILES ; do
	if [ ! -f "$FILE" ] ; then
		echo "ERROR: $FILE is not a file."
		continue
	fi
	# process the file
done

در این مثال هر گاه متغیر FILE حاوی نام یک فایل نباشد، تنها اجرای همان حلقه لغو میشود. و کنترل برنامه مجددا به ابتدای حلقه منتقل میشود.


Eman ‏۱۷ فوریهٔ ۲۰۱۲، ساعت ۱۱:۴۷ (UTC)

ابزارهای شخصی
گویش‌ها
فضاهای نام
عملکردها
گشتن
کتاب‌ها
مقاله‌ها
جعبه‌ابزار