BASH روشهای بسیاری برای ترکیب فرمانها جهت رسیدن به هدفهایمان ارائه میکند. قبلاً برخی از آنها را در عمل دیدهایم، اما اکنون بیایید کمی بیشتر به آنها بپردازیم.
BASH ساختارهایی دارد که دستورات مرکب نامیده میشوند، عبارتی چندپهلو، که با مفاهیم متفاوتی مرتبط میباشد. ما قبلاً بعضی از دستورات مرکب ارائه شده در BASH را دیدهایم -- جملههای
علاوه براین، به توابع و مستعارها که دستورات مرکب نیستند، اما به روش مشابهی عمل میکنند، نیز خواهیم پرداخت.
یک پوسته فرعی مانند یک پردازش فرزند است، غیر از اینکه اطلاعات بیشتری ارث میبرد. در یک خط لوله، پوستههای فرعی به طور ضمنی برای هر فرمان ایجاد میگردند. همچنین به طور صریح نیز با به کار بردن پرانتزها در اطراف دستور، ایجاد میشوند:
$( cd /tmp|| exit1 ; date> timestamp) $ pwd/home/lhunath
موقعی که پوسته فرعی خاتمه مییابد، اثر دستور cd از بین رفته است -- ما همانجایی هستیم که از آنجا شروع کرده بودیم. همچنین، هر متغیری که در پوسته فرعی تنظیم گردیده، قابل یادآوری نیست. میتوانید پوسته فرعی را به صورت پوسته موقتی در نظر بگیرید. برای جزئیات بیشتر پوسته فرعی را ملاحظه کنید.
توجه داشته باشید که در این مثال، اگر فرمان cd ناموفق باشد، دستور exit
قبلاً با این موضوع در گروه بندی جملات برخورد کردهایم، با وجود آن در ضمن این فصل تکرار میشود.
با استفاده از ابروها، دستورات را میتوان گروهبندی نمود. این تا حدودی مانند پوستههای فرعی به نظر میآید، اما اینطور نیست. دستورات گروهی مانند هر چیز دیگر در همان پوسته اجرا میشوند نه در یک شل جدید.
دستورات گروهی میتوانند برای اجرای دستورات چندگانه به کار رفته و یک تغییر مسیر منفردِ مؤثر بر تمام آنها داشته باشند:
${ echo "Starting at$( date) "; rsync-av . /backup ; echo "Finishing at$( date) "; } > backup.log 2 >& 1
یک زیر پوسته در این وضعیت زیادهروی خواهد بود، به دلیل آنکه نیازی به یک محیط موقتی نداریم. هر چند که، یک پوسته فرعی نیز کار خواهد کرد.
گروههای دستورات همچنین برای کوتاه کردن وظایف معین متداول، سودمند میباشند:
$[[ -f $ CONFIGFILE ]] || { echo "Config file$ CONFIGFILE not found">& 2 ; exit1 ; }
این را با روایت رسمی آن مقایسه کنید:
$if [[ ! -f $ CONFIGFILE ]] ; then > echo "Config file$ CONFIGFILE not found">& 2 > exit1 >fi
پوسته فرعی در اینجا کار نخوهد کرد، زیرا دستور exit
گروه دستورات، همچنین برای تنظیم متغیرها در حالتهای غیر معمول، به کار میرود:
$ echo "cat > mouse > dog"> inputfile ${ reada ; readb ; readc ; } < inputfile $ echo "$ b "mouse
خواندن دومین سطر از یک فایل، بدون یک گروه دستورات، که خواندن چندگانه دستورات read از یک توصیفگر فایل باز، بدون بازگشت هر دفعه به ابتدای فایل را مجاز میکند، بینهایت دشوار خواهد بود. با این مورد مقایسه کنید:
$ reada < inputfile $ readb < inputfile $ readc < inputfile $ echo "$ b "cat
ابداً آنچه ما میخواستیم، نیست!
اگر آنگونه که ما در اینجا نشان دادیم، گروه دستورات در یک سطر باشد، سپس باید یک سمیکالن قبل از بستن گروه با
${ > echo "Starting at$( date) " > rsync-av . /backup > echo "Finishing at$( date) " >} > backup.log2 >& 1
BASH دارای چند روش مختلف است، برای آنکه به او بگوییم، به جای عملیات روی رشتهها، میخواهیم ارزیابی محاسباتی انجام بدهیم. اجازه دهید یکی یکی به آنها بپردازیم.
اولین روش دستور let میباشد:
$ unseta ; a = 4+ 5 $ echo$ a 4+5 $ leta =4+ 5 $ echo$ a 9
اگر عبارت را نقلقولی کنید، میتوانید از فاصلهها، پرانتزها و غیره استفاده کنید:
$ leta ='( 5 +2 )*3 '
برای لیست کامل عملگرهای معتبر، دستور help let یا مستندات را ببینید.
بعد دستور مرکب ارزیابی محاسباتی حقیقی است:
$(( a =(5+2)*3))
این معادل دستور let میباشد، اما میتوانیم آن را به عنوان یک فرمان نیز به کار ببریم، به عنوان مثال در یک جمله
$if (($ a ==21 ));then echo 'Blackjack!'; fi
عملگرهایی مانند
هرچند اگر یک دستور مرکب نباشد، یک ترکیب دستوری معتبر جایگزینی حسابی (یا یک عبارت حسابی) نیز میباشد:
$ echo "There are$(($ rows * $ columns )) cells"
بخش درونی
خوانندگانی که با زبان برنامهنویسی C آشنا هستند، ممکن است مایل باشند بدانند که
$(( abs = (a >=0 ) ?a : -a ))
و یکی هم استفاده از مقدار صحیح به عنوان مقدار درست:
$if (( flag ));then echo "uh oh, our flag is up"; fi
توجه نمایید که ما متغیرها را در داخل
یک مطلب نهایی وجود دارد ، که باید در باره
$flag = 0 # no error $while readline ; do >if [[ $ line = * err *]] ; then flag = 1 ; fi >done < inputfile $if (( flag ));then echo "oh no"; fi
توابع در اسکریپتهای bash خیلی جذاب هستند. بلوکهایی از فرمانها میباشند، خیلی مشابه اسکریپتهای عادی، که شاید شما بنویسید، به جز آنکه به صورت فایلهای جداگانه نیستند. هرچند که، آنها درست مانند اسکریپتها شناسهها را میپذیرند -- و بر خلاف اسکریپتها، اگر شما بخواهید، میتوانند بر متغیرهای داخل اسکریپتهای شما تأثیرگذار باشند. برای مثال این مورد را ملاحظه کنید:
$sum() { > echo "$1 + $2 = $(($1 + $2)) " >}
این نمونه وقتی اجرا شود، مطلقاً کاری انجام نمیدهد. این به آن دلیل است که، فقط درحافظه ذخیره میشود، خیلی همانند یک متغیر، اما تا موقعی که هنوز فراخوانی نشده است. برای اجرای تابع، به این طریق باید عمل کنید:
$sum 1 4 1 + 4 = 5
شگفتا! اکنون یک ماشین حساب ابتدایی داریم، و جایگزین بالقوه مقرون به صرفهتری برای یک کودک پنجساله.
اگر بخواهید توابع را در داخل اسکریپتها تعبیه کنید، که بسیار مناسبتر خواهد بود، آنوقت لازم است متوجه باشید، پارامترهایی که با اسکریپت به کار میبرید، لزوماً نبایستی همان پارامترهای داده شده به تابع باشند. برای پوشاندن این تابع در داخل یک اسکریپت، باید چنین فایلی بنویسیم:
به طوری که میتوانید ملاحظه کنید، ما دو پارامتر اسکریپت را به تابع داخل آن دادهایم، اما میتوانستیم هر پارامتر دیگری که مایل باشیم به تابع بدهیم، (اگرچه ، این حالت فقط موجب سردرگمی کاربران استفاده کننده از آن خواهد شد).
توابع در اسکریپت چند هدف را برآورده میسازند. اول آنکه یک بلوک از کدها که وظیفه معینی انجام میدهند را مجزا میکنند، به طوری که مانع درهم ریختگی سایر کدها میگردد. این مطلب تا وقتی اعتدال را رعایت میکنید، به شما کمک میکند، کدهای خواناتر بنویسید. ( پرش در طول اسکریپت برای پیگردی 7تابع جهت کشف آنکه یک دستور منفرد چه کار میکند، تأثیر منفی خواهد داشت، بنابراین درنظر داشته باشید کاری که انجام میدهید، قابل فهم باشد.) دوم، میسر نمودن استفاده مجدد از کد با تغییر جزئی شناسهها است.
این یک مثال کمتر فاقد کیفیت:
1 #!/bin/bash
2 open() {
3 case "$ 1" in
4 *.mp3|*.ogg|*.wav|*.flac|*.wma) xmms "$ 1";;
5 *.jpg|*.gif|*.png|*.bmp) display "$ 1";;
6 *.avi|*.mpg|*.mp4|*.wmv) mplayer "$ 1";;
7 esac
8 }
9 for file ; do
10 open "$ file "
11 done
در اینجا تابعی به نام
به طوری که شاید ملاحظه نموده باشید، پارامترهای تابع غیر از پارامترهای اسکریپت هستند.
همچنین، تابع ممکن است متغیرهای محلی داشته باشد، که با دستور داخلی local یا declare تعریف شده باشند. این امر شما را قادر میسازد بدون احتمال رونویسی متغیرهای مهم، توابع را فراخوانی کنید. برای نمونه:
count() { locali for (( i =1 ;i <=$1;i ++));do echo$ i ; done echo 'Ah, ah, ah!'} for (( i =1;i <=3;i ++));do count $ i ;done
متغیر
توابع میتوانند خودشان را نیز به طور بازگشتی فراخوانی نمایند، اما در اینجا به آن نمیپردازیم. شاید بعداً!
مستعارها در نگاه اول ظاهراً مشابه توابع هستند، اما در بررسی عمیقتر، آنها رفتار کاملا متفاوتی دارند.
اساساً مستعارها، میانبرهایی برای استفاده درفایلهای .bashrc جهت آسانتر نمودن روند کارهای شما میباشند. آنها به طور معمول چنین به نظر میآیند:
$ alias ls='ls--color=auto '
BASH اولین کلمه هر دستور ساده را بررسی میکند، که ببیند آیا یک مستعار است، و اگر چنین باشد، یک جایگزینی ساده متن را انجام میدهد. بنابراین، اگر شما تایپ کنید
$ ls /tmp
BASH چنان عمل میکند، که گویی تایپ نمودهاید
$ ls--color=auto /tmp
اگر خواسته باشید این توانایی را در یک تابع ایجاد کنید، به این شکل خواهد شد:
$ unalias ls $ls() { command ls--color=auto " $@ "; }
همانند یک گروه دستور، اگر بخواهیم تمام آن را در یک سطر بنویسیم، لازم است یک سمیکالن (
مستعارها تا زمانی که شما از آنها نخواهید همچون توابع کار کنند، مناسب هستند. اگر رفتار پیچیدهای مورد انتظار شماست، به جای آن از تابع استفاده کنید.
برای از بین بردن یک تابع یا متغیراز محیط جاری پوسته خود، دستور unset را به کار ببرید.
$ unsetmyfunction
برای از بین بردن مستعار، فرمان unalias را به کار ببرید.
$ unalias rm