استفاده از عملگرهای شرطی ساده و موجز میباشد، به شرطی که بخواهیم کنترل خطای سادهای انجام دهیم. گرچه، موقعی که بخواهیم در صورت صحیح بودن یک شرط، جملات چندگانهای را اجرا کنیم، یا نیاز به بررسی شرطهای چندگانه داشته باشیم، مسائل قدری خطرناکتر میشوند.
فرض کنید میخواهید یک فایل را در صورت وجود کلمه معین "good" در آن و نیز عدم وجود کلمه مشخص "bad" در آن حذف کنید. با استفاده از grep ( فرمانی که ورودیاش را برای الگوهای تعیین شده بررسی میکند)، این شرایط را به این صورت ترجمه میکنیم:
grep | exit status 0 (success) if "$file" contains 'goodword' |
| exit status 0 (success) if "$file" does not contain 'badword' |
ما از گزینه
علامت
حال برای متصل کردن این شرطها به یکدیگر و ربط دادن حذف فایل به موفقیت هر دو، میتوانستیم از عملگرهای شرطی استفاده کنیم:
$ grep-q goodword "$ file "&& ! grep-q badword "$ file "&& rm "$ file "
این بخوبی کار میکند( در حقیقت میتوانیم هر تعداد از
$ grep-q goodword "$ file "&& ! grep-q badword "$ file"&& rm "$ file "|| echo "Couldn't delete:$ file ">& 2
این هم ظاهراً در نگاه اول صحیح است. اگر کد خروج rm برابر
اما مشکلی وجود دارد. موقعی که ما یک توالی از دستوراتی که با
همچنین تصور کنید اولین grep ناموفق است(کد وضعیت یک میشود) . Bash حالا
وقتی فقط پیغام خطای اشتباهی دریافت میکنید انعکاس خیلی بدی ندارد، اما اگر دقیق نباشید، سرانجام در کدهای خطرناکتر، این اتفاق خواهد افتاد. شما که نمیخواهید به طور تصادفی در اثر نارسایی منطق برنامه خود فایلی را حذف یا رونویسی نمایید!
نقص منطق ما در این واقعیت است که ما میخواهیم فرمانهای rm و echo وابسته به یکدیگر باشند. دستور echo مربوط به rm میباشد، نه مربوط به grepها. بنابراین آنچه ما لازم داریم، گروهبندی آنها است. گروهبندی با استفاده از ابروها انجام میگردد:
$ grep-q goodword "$ file "&& ! grep-q badword "$ file "&& { rm "$ file "|| echo "Couldn't delete:$ file ">& 2; }
(
حالا دستورات rm و echo را با هم گروهبندی نمودهایم. این به طورمؤثر و کارامدی به معنای آنست که گروه به عنوان یک جمله در نظر گرفته میشود، نه چند دستور. برگردیم به موقعیتی که اولین دستور grep ما ناموفق بود، حالا BASH به جای اینکه به جمله
گروهبندی دستورات برای موارد بیشتری غیر از عملگرهای شرطی نیز میتواند به کار رود. ممکن است بخواهیم دستورات را گروهبندی کنیم تا یک ورودی را به این گروه تغییر مسیر بدهیم، نه فقط به یکی از دستورات:
{ read firstLine read secondLinewhile read otherLine;do somethingdone } < file
در اینجا ما
یک مورد استفاده رایج دیگر از گروهبندی، مدیریت خطای ساده است:
cd "$ appdir "|| { echo "Please create the appdir and try again">& 2; exit 1; }
حال که میدانیم کدهای خروج چیستند، و یک کد خروج صفر به معنای اجرای موفق یک دستور میباشد، استفاده از این اطلاعات را خواهیم آموخت. سادهترین روش انجام یک عمل معین بر اساس موفقیت دستور قبلی از راه به کارگیری عملگرهای کنترلی میباشد. این عملگرها
بیایید این مطلب را در عمل به کار ببریم:
$ mkdir d
&& cd d
این مثال ساده دو دستور دارد، mkdir d و cd d. میتوانستید از یک سمیکالن در آنجا برای جدا کردن دستورهاو اجرای ترتیبی آنها استفاده کنید، اما ما چیزی بیش از آن میخواهیم. در مثال فوق، BASH فرمان mkdir d را اجرا میکند، سپس
مثالی دیگر:
$ rm /etc/some_file.conf
|| echo "I couldn't remove the file"rm: cannot remove `/etc/some_file.conf': No such file or directory I couldn't remove the file
به طور کلی، متصل کردن چند دستور کنترلی در یک جمله منفرد ایده خوبی نیست(ما این مطلب را در بخش بعدی باز خواهیم کرد).
وقتی با عبارتهای شرطی سر و کار دارید خیلی هواخواه این عملگرها نباشید. اینها میتوانند درک اسکریپت شما را دشوار سازند، به ویژه برای کسی که به نگهداری آن منصوب شده و خودش اسکریپت را ننوشته است.
در مستندات گنو: Lists of Commands
عملگرهای کنترل: این عملگرها برای پیوند زدن دستورها با یکدیگر استفاده میشوند. آنها کد خروج دستور قبلی را برای تعیین اجرا یا عدم اجرای دستور بعدی بررسی میکنند.
فهرست مطالب
اجرای ترتیبی فرمانها به جای خود، اما برای دستیابی به منطق پیشرفته در اسکریپتهایتان یا در خط فرمان یک جملهای، به شرطها و بررسیها نیاز دارید. بررسیها تعیین میکنند که یک مطلبی صحیح است یا غلط. شرطها برای تصمیمسازی در مورد انجام فرامینی در اسکریپت به کار میروند.
از هر دستور موقعیکه خاتمه مییابد یک کد خروج حاصل میشود. این کد خروج توسط هر برنامهای که آن دستور را اجرا نموده برای تعیین آنکه مقصودش به درستی انجام شده یا نه استفاده میشود. این کد خروج مشابه مقدار برگشتی از توابع میباشد. این کد یک عدد صحیح از صفر تا ۲۵۵ میباشد. مطابق قرارداد از صفر برای مشخص نمودن موفقیت استفاده میکنیم، وهر عدد دیگر بیانگر نوعی شکست میباشد. هر برنامه معینی، عدد خاصی را برای اشاره به آنکه دقیقاً چه اشتباهی رخ داده به کار میبرد.
به عنوان مثال، دستور ping بستههای ICMP را در شبکه برای یک میزبان معین ارسال میکند. به طور معمول آن میزبان، با برگشت دادن دقیق همان بسته پاسخ میدهد. به این طریق میتوانیم کنترل کنیم که آیا میتوانیم یک ارتباط با میزبان راه دور برقرار کنیم. دستورping دامنهای از کدهای خروج دارد که اگر مشکلی باشد، میتواند به ما بگوید، چه چیز نادرست است:
از مستندات ping لینوکس:
اگر ping هیچ بسته بازگشتی دریافت نکند، با کد 1 خارج خواهد شد. اگر یک شماره بسته و یک محدوده زمانی تعیین شده باشد، و شمارش بستههای دریافتی در زمان تعیین شده با عدد کمتری اعلام شود نیز با کد 1 خارج میشود. در سایر موارد خطا با کد 2 خارج میشود. در غیر اینصورت با کد صفر خارج میشود. و استفاده از کد خروج امکان آن را فراهم میکند که ببینیم میزبان فعال میباشد یا خیر.
پارامتر ویژه
$ ping Godping: unknown host God $ echo$? 2 $ ping-c 1 -W 1 1.1.1.1PING 1.1.1.1 (1.1.1.1) 56(84) bytes of data. --- 1.1.1.1 ping statistics --- 1 packets transmitted, 0 received, 100% packet loss, time 0ms $ echo$? 1
همواره باید مطمئن شوید که اسکریپت شما در صورت وقوع رخداد ناخواسته در جریان اجرایش، کد خروج غیر صفر برمیگرداند. میتوانید با استفاده از دستور داخلی exit این کار را عملی کنید:
rm file|| { echo 'Could not delete file!'>&2; exit 1; }
در مستندات گنو: Exit Status
کد خروج / وضعیت خروج: هنگامی که یک دستور خاتمه مییابد به والدش( در موقعیت ما همیشه پوستهای میشود که شروع کردهایم) ، وضعیت خروج خود را گزارش میکند. این وضعیت با یک عدد از صفر تا ۲۵۵ نمایانده میشود. این کد اشارهای به موفقیت اجرای دستور است.
عبارتهای منظم(
BASH از عبارت منظم توسعه یافته (
الگوهای عبارت منظم که برای گرفتن گروهها(پرانتزها)به کار میروند، رشتههای گرفته شدهشان را برای بازیابی بعدی، به متغیر
اجازه دهید، تشریح کنم که regex در BASHچگونه کار میکند:
$langRegex ='(..)_(..)' $if [[ $ langRegexLANG =~ $]] >then > echo "Your country code (ISO 3166-1-alpha-2) is$ { BASH_REMATCH[2] } ." > echo "Your language code (ISO 639-1) is$ { BASH_REMATCH[1] } ." >else > echo "Your locale was not recognised" >fi
آگاه باشید که تفکیک کلمه regex در BASH از نگارش
از آن جهت که روش regex مورد استفاده در
برای سازگاری سراسری ( اجتناب از الزام به پوشش کاراکترهای خاص ) از یک متغیر برای ذخیره عبارت منظم خود استفاده کنید، مانند.
همچنین، بخش E14 از Chet Ramey's Bash FAQ، را ملاحظه نمایید.
در مستندات گنو: Regex(3)
در پرسش و پاسخهای رایج:
من میخواهم بدون تکرار n مرتبه
عبارت منظم: یک عبارت منظم، الگوی پبچیدهتری است که میتواند برای انطباق با رشتههای معین به کار برود( اما بر خلاف جانشینها نمیتواند به نام فایلها بسط داده شود ).
جانشینها(globs) اگر فقط برای راحتی باور نکردنیشان باشد هم، مفهوم بسیار مهمی در BASH میباشند. درک صحیح globها به طُرق بسیاری برای شما مفید خواهد بود. جانشینها اساساً الگوهایی میباشند که میتوانند برای انطباق با نام فایلها یا سایر رشتهها به کار بروند.
جانشینها مرکب از کاراکترهای معمولی و فوق کاراکترها هستند. فوق کاراکترها، آن کاراکترهایی هستند که معنی ویژهای دارند. فوق کاراکترهای اصلی عباتند از:
جانشینها به طور صریح از هر دو طرف مهار میگردند. این به آن معناست که یک جانشین بایستی بر تمام رشته( نام فایل یا رشته دادهای) منطبق شود.
در اینجا مثالی در مورد اینکه چگونه میتوانیم از الگوهای جانشین برای بسط نام فایلها استفاده کنیم:
$ lsa abc b c $ echo* a abc b c $ echoa * a abc
BASH جانشین را میبیند، به عنوان مثال
BASH بسط نام فایل را بعد از تفکیک کلمهای، که قبلاً انجام داده است، اجرا مینماید، بنابراین، نام فایلهای ایجاد شده توسط جانشین، همیشه به طور صحیح به کار خواهد رفت. برای مثال:
$ touch "a b.txt" $ lsa b.txt $ rm* $ ls $
در اینجا،
$ lsa b.txt $for file in`ls`; do rm"$ file ";done rm: cannot remove `a': No such file or directory rm: cannot remove `b.txt': No such file or directory $for file in*; do rm"$ file ";done $ ls $
در اینجا از فرمان
BASH همچنین از یک ویژگی به نام جانشینهای توسعه یافته پشتیبانی میکند. این جانشینها در ماهیت قدرتمندتر هستند، از لحاظ فنی، آنها معادل عبارتهای معمولی هستند، اگر چه ساختار آنها به ظاهر متفاوت با آنچه اکثریت مردم به کار میبرند، باشد. این ویژگی به طور پیشفرض غیر فعال است، لیکن میتواند با دستور shopt، که برای تغییر وضعیت گزینههای پوسته به کار میرود، فعال شود. این دستور کوتهنوشتی از عبارت
$ shopt-s extglob
کلمه list داخل پرانتزها لیستی از جانشینهای معمولی یا توسعه یافته میباشد که با کاراکتر
$ lsnames.txt tokyo.jpg california.bmp $ echo!(* jpg |*bmp )names.txt
در اینجا الگوی جانشین(list) به هر چیزی که بر
علاوه بر بسط نام فایل، از جانشینها میتوان برای بررسی انطباق دادهها با یک قالب مشخص شده نیز استفاده نمود. برای مثال، ممکن است نام فایلی را داده باشیم، و انتظار عملیات متفاوت بر اساس پسوند فایل داشته باشیم:
$filename = "somefile.jpg " $if [[ $ filename = * .jpg ]] ; then > echo "$ filename is a jpeg" >fi somefile.jpg is a jpeg
کلمه کلیدی
سپس،بسط ابرو را داریم. از نظر تکنیکی بسط ابرو در زمره جانشینها نمیباشد، اما مشابه آن است. جانشینها فقط به نام فایلهای حقیقی بسط مییابند، در جایی که بسط ابرو به هر جایگردی از الگو بسط خواهد یافت. در اینجا چگونگی کارکرد آن:
$ echo th{ e,a} nthen than $ echo{ /home/* ,/root} /.* profile/home/axxo/.bash_profile /home/lhunath/.profile /root/.bash_profile /root/.profile $ echo{ 1..9} 1 2 3 4 5 6 7 8 9 $ echo{ 0,1}{ 0..9} 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19
تکرار سودمند:
برای به شمار آوردن فایلها همواره باید از جانشینها به جای ls(یا مشابه آن) استفاده کنید. جانشینها همیشه به طور ایمن و با حداقل ریسک ایجاد باگ بسط مییابند.
گاهی ممکن است با نام فایلهای خیلی عجیب روبرو شوید. اکثر اسکریپتها برای هر یک از مواردی که در نتیجه استفاده از آنها ممکن است حاصل شود، بررسی نمیشوند. اجازه ندهید اسکریپت شما نیز یکی از آنها باشد!
در مستندات گنو: Pattern Matching
در پرسش و پاسخهای رایج:
چگونه میتوانم از AND/OR/NOT منطقی در الگو(جانشین) پوسته استفاده کنم؟
جانشین( glob ): یک جانشین رشتهایست که میتواند با نام فایلها یا رشتههای معینی منطبق گردد.