تا اینجا آموختهاید چگونه برخی تصمیمگیری های اساسی در اسکریپتهایتان را بسازید. اگر چه، برای انجام همه انواع وظایفی که ممکن است از اسکریپت بخواهیم کافی نمیباشد. گاهی اوقات نیاز به تکرار برخی کارها داریم. برای همین، کاربرد یک حلقه لازم است. دو نوع اصلی ازحلقه( به اضافه نوع دیگری) وجود دارد، و استفاده از نوع صحیح حلقه به شما در نگهداری خوانایی و قابلیت پشتیبانی اسکریپتهایتان کمک میکند.
دو نوع اساسی حلقهها
هر شکل از حلقهها با کلمهکلیدی
در عمل، حلقهها برای انواع مختلفی از وظایف به کار میروند. حلقه
در اینجا چند مثال برای تشریح تفاوتها و همچنین شباهتهای حلقهها میآوریم. (یادآوری: در اکثر سیستمعاملها، برای کشتن برنامهای که در ترمینال در حال اجرا است از ترکیب کلیدی
$while true >do echo "Infinite loop" >done
$while ! ping-c 1 -W 1 1.1.1.1; do > echo "still waiting for 1.1.1.1" > sleep 1 >done
$(( i =10 ));while (( >i >0 ))do echo "$ i empty cans of beer." >(( >i -- ))done $for (( >i =10 ;i >0 ;i -- ))do echo "$ i empty cans of beer." >done $for i in { 10..1 } >do echo "$ i empty cans of beer." >done
سه حلقه آخری با ترکیب متفاوت، دقیقاً به نتیجه یکسانی میرسند. در تجربه اسکریپتنویسی شل خود بارها با این مورد مواجه میشوید. تقریباً همیشه راهکارهای چندگانهای برای حل یک مسئله موجود است. به زودی تشحیص مهارت شما در حل مسئله نخواهد بود، آنقدر که درچگونگی
بیایید نگاه نزدیکتری به آن مثال آخری داشته باشیم، زیرا اگر چه از دو حلقه
به طوری که قبلاً اشاره کردهام:
$for i in 10 9 8 7 6 5 4 3 2 1 >do echo "$ i empty cans of beer." >done
BASH کاراکترهای بین کلمهکلیدی
در نتیجه،
$ lsThe best song in the world.mp3 $for file in $ (ls* .mp3 ) >do rm "$file" >done rm: cannot remove `The': No such file or directory rm: cannot remove `best': No such file or directory rm: cannot remove `song': No such file or directory rm: cannot remove `in': No such file or directory rm: cannot remove `the': No such file or directory rm: cannot remove `world.mp3': No such file or directory
شما از قبل نسبت به نقلقولی کردن
خواهید گفت، آن را نقلقولی میکنم؟ اجازه دهید فایل دیگری اضافه کنم:
$ lsThe best song in the world.mp3 The worst song in the world.mp3 $for file in "$(ls * .mp3)" >do rm "$ file" >done rm: cannot remove `The best song in the world.mp3 The worst song in the world.mp3': No such file or directory
نقلقولها به راستی از فضای سفید در نام فایلهای شما محافظت میکنند، اما چیزی بیش از آن انجام میدهند. نقلقولها از تمام فضاهای سفید خروجی فرمان ls محافظت خواهند کرد. راهی وجود ندارد که BASH بتواند تشخیص بدهد کدام بخشهای خروجی فرمان ls نام فایلها را نمایندگی میکنند. خروجی فرمان ls یک رشته ساده است، و BASH با آن به همین عنوان رفتار میکند. بعد
بنابراین چه کار بکنیم؟ به طوری که قبلاً پیشنهاد نمودم، جانشینها بهترین دوست شما هستند:
$for file in * .mp3 >do rm "$ file" >done
حالا، BASH میداند که با نام فایلها سروکار دارد، و نام فایها را میشناسد، و بنابراین به طور مطلوبی آنها راتفکیک میکند. نتیجه بسط جابشین چنین است:
حالا بیایید به حلقه
$ # ماشین نوشیدنی، نوشیدنیها را در ازای بهای ۲۰ سنت تحویل میدهد $while read-p $ 'The sweet machine.\n Insert 20c and enter your name: 'name >do echo "The machine spits out three lollipops at$ name ." >done
$ # هر پنج دقیقه یکبار ایمیل شما را بررسی میکند $while sleep 300 >do kmail--check >done
$ # برای برخط(آنلاین) شدن مجدد میزبان منتظر میماند $while ! ping-c 1 -W 1 "$ host " >do echo "$ host is still unavailable." >done ; echo-e "$ host is available again.\a"
حلقه
$ # برای برگشت میزبان به حالت آماده برقراری ارتباط منتظر میماند $until ping-c 1 -W 1 "$ host " >do echo "$ host is still unavailable." >done ; echo-e "$ host is available again.\a"
در عمل، اکثر مردم حقیقتاً از حلقه
بالإخره، از دستور داخلی continue برای پرش به جلو بدون اجرای بقیه بدنه و اجرای دور بعدی تکرار حلقه، و دستور داخلی break برای پریدن به خارج از حلقه و ادامه دستورات پس از حلقه در اسکریپت، میتوانید استفاده کنید. این دستورات با هر دو حلقه
در مستندات گنو: Looping Constructs
در پرسش و پاسخهای رایج:
چگونه میتوانم یک دستور را با تمام فایلهای دارای پسوند .gz اجرا کنم؟
چگونه میتوانم از اعدادی که با صفر شروع میشوند مثل 01 و 02 در یک حلقه استفاده کنم؟
چطو میتوانم نام فایلهای شامل کاراکتر فاصله یا سطر جدید یا هر دو را پیدا کرده وبا آنها کار کنم؟
میخواهم بررسی کنم که آیایک کلمه در یک لیست وجود دارد( یا یک عنصر عضوی از یک مجموعه هست).
حلقه: یک حلقه ساختاری است که برای تکرار کد تا موقع تحقق یک وضعیت معین، طراحی میشود. در آن نقطه حلقه متوقف میشود و کد بعد از آن اجرا میگردد.
$if true >then echo "It was true." >else echo "It was false." >fi It was true.
در اینجا یک نمای کلی اساسی از
افراد مختلف شیوههای متفاوتی از نوشتن جملات
if commandsthen other commandsfi -------------------if commandsthen other commandsfi -------------------if commands; then other commandsfi
چند دستور وجود دارد که به طور ویژه برای بررسی موارد و بازگرداندن وضعیت خروج نسبت به آنچه تشخیص میدهند، طراحی گردیدهاند. اولین دستور از این قبیل test میباشد( که [ نیز شناخته میشود.) یک نگارش پیشرفتهتر آن
$if [ a= b ] >then echo "a is the same as b." >else echo "a is not the same as b." >fi a is not the same as b.
حال ببینیم که چرا
$myname = 'Greg Wooledge' yourname= 'Someone Else' $ [$ myname = $ yourname ]-bash: [: too many arguments
میتوانید حدس بزنید چه مشکلی موجب بروز خطا شده؟
دستور [ با شناسههای
$ ["$ myname " = "$ yourname " ]
در این حالت [ دومین شناسه را یک عملگر(
برای کمی مساعدت با ما، پوسته Korn یک سبک جدید بررسی شرطی را معرفی نموده(و BASH نیز آن را اخذ کرده). مؤلف اصل اینها که
یکی از ویژگیهای
$[[ $ filename = * .png]] && echo "$ filename looks like a PNG file"
ویژگی دیگر
$[[ $ me = $ you ]] # Fine. $[[ I am$ me = I am$ you ]] # Not fine!-bash: conditional binary operator expected -bash: syntax error near `am'
در این حالت، نیازی به نقلقولی کردن
$[[ "I am$ me "= "I am$ you "]]
همچنین، تفاوت ظریف زیرکانهای بین نقلقولی کردن و نکردن سمت راست مقایسه در
$foo = [a-z]*name = lhunath $[[ $ name = $ foo ]] && echo "Name$ name matches pattern$ foo "Name lhunath matches pattern [a-z]* $[[ $ name = "$ foo "]] || echo "Name$ name is not equal to the string$ foo "Name lhunath is not equal to the string [a-z]*
بررسی اول کنترل میکند که آیا
یادآوری: همواره اگر اطمینان ندارید نقلقولی کنید. اگر
میتوانید چندین دستور
$name = lhunath $if [[ $ name = "George"]] >then echo "Bonjour,$ name " >elif [[ $ name = "Hans"]] >then echo "Goeie dag,$ name " >elif [[ $ name = "Jack"]] >then echo "Good day,$ name " >else > echo "You're not George, Hans or Jack. Who the hell are you,$ name ?" >fi
حال که درک مناسبی از مسائلی که با نقلقولها ممکن است ایجاد شود به دست آوردهاید، بیایید به سایر ویژگیهایی که [ و
بررسیهایی که با [ ( که به عنوان test نیزشناخته میشود) پشتیبانی میشود:
-e FILE: اگر فایل موجود باشد صحیح است.
-f FILE: اگر فایل موجود معمولی باشد صحیح است.
-d FILE: اگر فایل یک دایرکتوری باشد صحیح است.
-h FILE: اگر فایل یک پیوند نمادین باشد صحیح است.
-r FILE: اگر فایل برای شما قابل خواندن باشد صحیح است.
-s FILE: اگر فایل موجود باشد وتهی نباشد صحیح است.
-t FD : اگر FD(توصیفگر فایل) در یک ترمینال باز شده باشد صحیح است.
-w FILE: اگر فایل برای شما قابل نوشتن باشد صحیح است.
-x FILE: اگر فایل برای شما قابل اجرا باشد صحیح است.
-O FILE: اگر فایل به طور مؤثر در مالکیت شما باشد صحیح است.
-G FILE: اگر فایل به طور مؤثر در مالکیت گروه شما باشد صحیح است.
FILE -nt FILE: اگر فایل اول جدیدتر از فایل دوم باشد صحیح است.
FILE -ot FILE: اگر فایل اول قدیمیتر از فایل دوم باشد صحیح است.
-z STRING: اگر رشته تهی باشد(طول آن صفر باشد) صحیح است.
-n STRING: اگر رشته تهی نباشد(طول آن صفر نباشد) صحیح است.
STRING = STRING: اگر رشته اول از هر نظر مانند دومی باشد صحیح است.
STRING != STRING: اگر رشته اول دقیقاً مانند رشته دوم نباشد صحیح است.
STRING < STRING:اگر در مرتبسازی رشته اول قبل از دومی قرار میگیرد صحیح است.
STRING > STRING: اگر رشته اول در مرتبسازی بعد از رشته دوم قرارمیگیرد صحیح است.
EXPR -a EXPR: اگر هر دوعبارت صحیح باشندصحیح است(and منطقی).
EXPR -o EXPR: اگر هر یک از دو عبارت صحیح باشد صحیح است(or منطقی).
! EXPR: نتیجه عبارت را معکوس میکند( NOTمنطقی).
INT -eq INT: اگر هر دو عدد صحیح دقیقاً برابر باشند صحیح است.
INT -ne INT: اگر هر دو عدد صحیح دقیقاً برابر نباشند، صحیح است.
INT -lt INT: اگر عدد صحیح اولی کوچکتر از دومی باشد صحیح است.
INT -gt INT: اگر عدد صحیح اولی از دومی بزرگتر باشد صحیح است.
INT -le INT: اگر عدد صحیح اولی کوچکتر یا مساوی دومی باشد صحیح است.
INT -ge INT: اگر عدد صحیح اولی بزرگتر یا مساوی دومی باشد صحیح است.
بررسیهای اضافی که فقط توسط
STRING = (or ==) PATTERN: مانند [ (یا test) مقایسه نمیکند، بلکه انطباق الگو انجام میشود. اگر رشته با الگوی جانشین منطبق گردد، صحیح است.
STRING =~ REGEX: اگر رشته با الگوی regex(عبارت منظم)تطبیق کند، صحیح است.
( EXPR ): پرانتزها میتوانند برای تغییر اولویت ارزیابیها به کار بروند.
EXPR && EXPR: خیلی مشابه عملگر
EXPR || EXPR: خیلی مشابه عملگر
چند مثال؟ حتماً:
$ test-e /etc/X11/xorg.conf&& echo 'Your Xorg is configured!'Your Xorg is configured! $ test-n "$ HOME "&& echo 'Your homedir is set!'Your homedir is set! $[[ boar!= bear]] && echo "Boars aren't bears."Boars aren't bears! $[[ boar!= b? ar]] && echo "Boars don't look like bears." $ $[[ $ DISPLAY ]] && echo "Your DISPLAY variable is not empty, you probably have Xorg running."Your DISPLAY variable is not empty, you probably have Xorg running. $[[ ! $ DISPLAY ]] && echo "Your DISPLAY variable is not not empty, you probably don't have Xorg running." $
تکرارمفید:
هنگامی که یک اسکریپت BASH ایجاد میکنید، همیشه باید از
وقتی یک اسکریپت پوسته مینویسید، که پس از اتمام ممکن است در محیطی که BASH در دسترس نباشد، به کار برود، باید از [ استفاده کنید، به دلیل آنکه به مراتب قابل حملتر میباشد. ( در حالیکه در BASH و برخی پوستههای دیگر، [ یک دستور داخلی است، به صورت یک برنامه خارجی نیز به خوبی در دسترس میباشد، یعنی به عنوان شناسه مثلاً exec و xargs کار خواهد کرد.)
هرگز از
if [ "$ food "= apple ]&& [ "$ drink "= tea ]; then echo "The meal is acceptable."fi
در پرسش و پاسخهای رایج:
چگونه میتوانم عبارتها را گروهبندی کنم، مثل (a
چطور میتوانم تعیین نمایم که آیا یک متغیر شامل یک زیر رشته هست؟
چگونه میتوانم بگویم که یک متغیر آیا محتوی یک عدد معتبر هست؟