7. حلقه ها

اکثر زبان‌ها، مفهوم حلقه را دارند : اگر بخواهیم کاری را بیست مرتبه تکرار کنیم، مایل نیستیم ،در بیست نوبت مجبور به تایپ کد،احتمالاً با یک تغییر جزئی، باشیم.
بنابراین در پوسته بورن ما حلقه‌های for و while را داریم. این تا حدودی کمتر از ویژگی‌های سایر زبان‌ها می‌باشد، اما کسی توقع ندارد، برنامه‌نویسی پوسته به قدرتمندی C باشد.

حلقه‌های For

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


for.sh
#!/bin/sh
for i in 1 2 3 4 5
do
  echo "Looping ... number $i"
done

این کد را اجرا کنید وببینید چه می‌کند، توجه نمایید که کمیت‌ها هر چیزی می‌توانند، باشند:


for2.sh
#!/bin/sh
for i in hello 1 * 2 goodbye 
do
  echo "Looping ... i is set to $i"
done

ارزش آزمودن داشت؟ مطمئن شوید، فهمیده‌اید که در این‌جا چه چیزی رخ می‌دهد. بدون * امتحان کنید و مفهوم را بگیرید، دومرتبه بخش کاراکترهای‌عام رابخوانید و مجدداً با قرار دادن * اجرا کنید. همچنین در دایرکتوری‌های متفاوت و نیز با * محصور شده در نقل‌قول دوگانه، و بامقدم کردن ممیزبرعکس به صورت ‎ (\*)‎ هم امتحان کنید.

در حالتی که شما در این لحظه به پوسته دسترسی ندارید ( دسترسی به شل در خلال خواندن این آموزش بسیار سودمند است )،نتایج دو اسکریپت فوق چنین است:

Looping .... number 1
Looping .... number 2
Looping .... number 3
Looping .... number 4
Looping .... number 5

و برای نمونه دوم:

			Looping ... i is set to hello
			Looping ... i is set to 1
			Looping ... i is set to (name of first file in current directory)
			... etc ...
			Looping ... i is set to (name of last file in current directory)
			Looping ... i is set to 2
			Looping ... i is set to goodbye

بنابراین، به طوری که می‌توانید ببینید for تا وقتی که به انتهای ورودی‌اش برسد، به سادگی، در میان هرآنچه به عنوان ورودی به آن داده شده، می‌چرخد.

حلقه‌های While

حلقه‌های while می‌توانند خیلی با مزه‌تر باشند! (منوط به تصور شما از بامزه، و این که اغلب چگونه از منزل خارج می‌شوید ... )


while.sh
#!/bin/sh
INPUT_STRING=hello
while [ "$INPUT_STRING" != "bye" ]
do
  echo "Please type something in (bye to quit)"
  read INPUT_STRING
  echo "You typed: $INPUT_STRING"
done

در این جا چه می‌شود، آیا تا موقعی‌که در مقابل اعلان کلمه "bye" را تایپ کنید، دستورات read و echo به طور نامحدود تکرار می‌شوند؟
بخش متغیرها - قسمت اول را برای فهمیدن، آن که چرامتغیر INPUT_STRING=hello را قبل از آزمایش آن مقداردهی نموده‌ایم، ملاحظه کنید. این یک حلقه تکرار، غیر از حلقه تکرار سنتی While می‌سازد.


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


while2.sh
#!/bin/sh
while :
do
  echo "Please type something in (^C to quit)"
  read INPUT_STRING
  echo "You typed: $INPUT_STRING"
done

ترفند سودمند دیگر حلقه ‎ while read f‎ می‌باشد. این مثال از ساختار case ، که ما بعداً پوشش خواهیم داد، استفاده می‌کند. این حلقه فایل myfile را سطر به سطر می‌خواند و زبان به کار رفته در هر سطر رابه شما اعلام می‌کند،.هر سطر از فایل باید با کاراکتر LF (سطر جدید)، تمام شود - اگر- cat myfile با یک سطر خالی به پایان نرسد، سطر پایانی پردازش نمی‌شود .


while3a.sh
#!/bin/sh
while read f
do
  case $f in
	hello)		echo English	;;
	howdy)		echo American	;;
	gday)		echo Australian	;;
	bonjour)	echo French	;;
	"guten tag")	echo German	;;
	*)		echo Unknown Language: $f
		;;
   esac
done < myfile

در بسیاری سیستم‌های یونیکس، به این صورت نیز می‌تواند انجام شود:


while3b.sh
#!/bin/sh
while f=`line`
do
  .. process f ..
done < myfile

اما چون ساختار while read f در هر سیستم ‎ *nix ‎ کار می‌کند، و به برنامه بیرونی line، وابسته نیست, قابل ترجیح است. بخش برنامه‌های‌خارجی را برای دیدن آن که چرا در این روش از علامت (`) استفاده می‌شود، ملاحظه نمایید.
اگر من در فرض‎ ("Unknown Language") ‎ در ساختار case بالا به ‎$i ‎  و نه ‎$f ‎   ارجاع می‌دادم - شما هیچ هشدار یا خطایی در این حالت دریافت نمی‌کردید، ولواینکه ‎$i‎ تعریف یا تعیین نشده بود. برای مثال:

$ i=THIS_IS_A_BUG
$ export i
$ ./while3.sh something
Unknown Language: THIS_IS_A_BUG
$

همینطور مطمئن شوید که از غلط تایپی اجتناب می‌کنید. این هم دلیل خوب دیگری برای استفاده از ‎${x}‎ و نه فقط ‎$x‎   - اگر به فرض ‎x="A"‎ باشد، وشما بخواهید بگویید "A1"، نمایش داده شود، به این دستور ‎echo ${x}1‎ نیاز دارید،چون ‎echo $x1‎ سعی خواهد نمود از متغیر ‎x1‎ استفاده کند، که موجود نیست، و شاید هم مقدار آن B2 باشد.


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


یک نکته قابل استفاده Bash (ولی پوسته بورن خیر)که اخیراً در Linux From Scratch آموخته‌ام. طرح این چنین است:

mkdir rc{0,1,2,3,4,5,6,S}.d

به جای کد طولانی‌تر:

for runlevel in 0 1 2 3 4 5 6 S
do
  mkdir rc${runlevel}.d
done

و این به صورت بازگشتی نیز می‌تواند، انجام شود:

$ cd /
$ ls -ld {,usr,usr/local}/{bin,sbin,lib}
drwxr-xr-x    2 root     root         4096 Oct 26 01:00 /bin
drwxr-xr-x    6 root     root         4096 Jan 16 17:09 /lib
drwxr-xr-x    2 root     root         4096 Oct 27 00:02 /sbin
drwxr-xr-x    2 root     root        40960 Jan 16 19:35 usr/bin
drwxr-xr-x   83 root     root        49152 Jan 16 17:23 usr/lib
drwxr-xr-x    2 root     root         4096 Jan 16 22:22 usr/local/bin
drwxr-xr-x    3 root     root         4096 Jan 16 19:17 usr/local/lib
drwxr-xr-x    2 root     root         4096 Dec 28 00:44 usr/local/sbin
drwxr-xr-x    2 root     root         8192 Dec 27 02:10 usr/sbin

ما از حلقه‌های while در بخش e Test و Case بیشتر استفاده می‌کنیم.

Steve Parker  نوشته  Bourne و Bash راهنمای آموزشی اسکریپت نویسی
لطفاً برای بهتر دیدن صفحه از فایرفاکس استفاده کنید