کنترل حلقه

فصل ‎11‎- حلقه‌ها و انشعاب‌ها

‎11.3‎- کنترل حلقه

 

Tournez cent tours, tournez mille tours,

Tournez souvent et tournez toujours . . .

--Verlaine(م: شاعر فرانسوی), "Chevaux de bois"

فرمانهای اثر گذار بر رفتار حلقه

break, continue

فرمان‌های کنترل حلقه break و continue‎[1]‎ به طور دقیق با همتاهایشان در سایر زبانهای برنامه‌نویسی مطابقت دارند. فرمان break حلقه را خاتمه می‌دهد (از آن بیرون می‌رود)، در حالیکه continue با پرش از روی تمام فرمانهای باقیمانده در آن دور بخصوص حلقه، باعث جهیدن به تکرار بعدی حلقه می‌گردد.

مثال ‎11-21‎. اثرات break و continue در یک حلقه

#!/bin/bash

LIMIT=19  #

echo
echo "Printing Numbers 1 through 20 (but not 3 and 11)."

a=0

while [ $a -le "$LIMIT" ]
do
 a=$(($a+1))

 if [ "$a" -eq 3 ] || [ "$a" -eq 11 ]  #  به غیر از ‎3‎ و ‎11‎
 then
   continue      #
 fi

 echo -n "$a "   #        این سطر برای ‎3‎ و ‎11‎ اجرا نمی‌شود.
done 

#                   
#  چرا حلقه تا ‎20‎ چاپ می‌کند؟

echo; echo

echo Printing Numbers 1 through 20, but something happens after 2.

#

# همان حلقه، اما با جایگزینی ‎break‎ به جای ‎continue‎

a=0

while [ "$a" -le "$LIMIT" ]
do
 a=$(($a+1))

 if [ "$a" -gt 2 ]
 then
   break  #
 fi

 echo -n "$a "
done

echo; echo; echo

exit 0

فرمان break ممکن است به طور اختیاری یک پارامتر بگیرد. یک break ساده فقط درونی‌ترین حلقه‌ای را که در آن جاسازی گردیده است، خاتمه می‌دهد، اما یک ‎break N‎ از N رده حلقه بیرون می‌رود.

مثال ‎11-22‎. بیرون رفتن از چند رده حلقه

#!/bin/bash
#

# ‎"break N"‎ از ‎N‎ سطح حلقه‌ها بیرون می‌رود.

for outerloop in 1 2 3 4 5
do
  echo -n "Group $outerloop:   "

  #
  for innerloop in 1 2 3 4 5
  do
    echo -n "$innerloop "

    if [ "$innerloop" -eq 3 ]
    then
      break  # ‎break 2‎ را برای دیدن اینکه چه می‌شود، امتحان کنید.
             #      ( از هر دو حلقه داخلی و خارجی بیرون می‌رود. )
    fi
  done
  #

  echo
done  

echo

exit 0

فرمان continue نیز، همانند break، به طور اختیاری یک پارامتر قبول می‌کند. یک continue ساده، تکرار فعلی داخل حلقه‌اش را پیش از موقع قطع کرده و دور بعدی را شروع می‌کند. یک ‎continue N‎ تمام تکرارهای باقیمانده سطح حلقه‌اش را فسخ می‌کند و تکرار بعدی حلقه را در N سطح بالاتر ادامه می‌دهد.

مثال ‎11-23‎. ادامه در سطح بالاتر حلقه

#!/bin/bash
# فرمان ‎"continue N"‎ در Nمین سطح حلقه ادامه می‌دهد.

for outer in I II III IV V           #
do
  echo; echo -n "Group $outer: "

  #
  for inner in 1 2 3 4 5 6 7 8 9 10  #
  do

    if [[ "$inner" -eq 7 && "$outer" = "III" ]]
    then
      continue 2  #
                  #  
                  #                     ‎"continue"‎ ساده تعویض کنید.
    fi  

    echo -n "$inner "   #  ‎7 8 9 10‎ در «گروه ‎III‎» منعکس نخواهند شد.
  done  
  #

done

echo; echo

#                            
# یک کاربرد با معنی برای ‎"continue N"‎ در یک اسکریپت طرح کنید.

exit 0

مثال ‎11-24‎. کاربرد ‎continue N‎ در یک وظیفه واقعی

# ‎Albert Reiner‎ یک نمونه از چگونگی استفاده از ‎"continue N"‎ را ارایه می‌کند:
#

#
#+
#+
#+            
#      آنوقت معمولاً چیزی مشابه مورد زیر را با هر دستگاه ‎nohup‎ می‌کنم:

while true
do
  for n in .iso.*
  do
    [ "$n" = ".iso.opts" ] && continue
    beta=${n#.iso.}
    [ -r .Iso.$beta ] && continue
    [ -r .lock.$beta ] && sleep 10 && continue
    lockfile -r0 .lock.$beta || continue
    echo -n "$beta: " `date`
    run-isotherm $beta
    date
    ls -alF .Iso.$beta
    [ -r .Iso.$beta ] && rm -f .lock.$beta
    continue 2
  done
  break
done

exit 0

#   جزییات، محصوصاً ‎sleep N‎ ویژه برنامه کاربردی
#+    

while true
do
  for job in {pattern}
  do
    {job already done or running} && continue
    {mark job as running, do job, mark job as done}
    continue 2
  done
  break        # یا چیزی مانند ‎'sleep 600'‎ برای اجتناب از خاتمه یافتن.
done

#  بدین طریق اسکریپت فقط موقعی متوقف خواهد شد که کار دیگری برای اجرا وجود
#+  نداشته باشد (از جمله کارهایی که در حین اجرا اضافه گردیده‌اند). از طریق
#+کاربرد فایل‌های قفل مناسب می‌تواند بدون دونسخه‌ای کردن محاسبات (که در مورد
#+ من بیش از ساعت‌ها کار می‌برد، از اینرو می‌خواهم از آن پرهیز نمایم) به طور
#+همزمان در چندین ماشین اجرا بشود. همچنین چون جستجو همیشه دوباره از ابتدا
#+    شروع می‌شود، شخص می‌تواند اولویت در نام فایلها را نیز کد گذاری نماید.
#+البته شخص می‌تواند این کار را بدون «‎continue 2‎» نیز انجام دهد، اما آنوقت
#+می‌باید به طور واقعی کنترل می‌کرد که به هر حال کار معینی انجام شده یا خیر‏
#+                     (برای اینکه ما باید بلافاصله سراغ کار بعدی می‌رفتیم)
#+(در حالتی که قبل از کنترل برای یک کار جدید، خاتمه بدهیم یا به مدت طولانی
#+                                                       غیر فعال بشویم.)

Caution

درک ساختار ‎continue N‎ دشوار و استفاده از آن در یک مضمون معنادار، مهارت‌آمیز است. شاید پرهیز از آن مناسب‌تر باشد.

یادداشت‌ها

[1]

این فرمانها builtin پوسته هستند، در حالیکه سایر فرمانهای حلقه، از قبیل while و case، کلمه کلیدی هستند.