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 بیشتر استفاده میکنیم.