در این درس، به چگونگی افزودن هوش به اسکریپتمان نگاه خواهیم نمود. تا اینجا، اسکریپت پروژه ما تنها از یک توالی فرمانها تشکیل گردیده است که در سطر اول شروع میشود و تا رسیدن به انتها سطر به سطر ادامه مییابد. اکثر برنامهها کاری بسیار بیش از این انجام میدهند. آنها تصمیمگیری میکنند و بر اساس شرایط، متفاوت عمل میکنند.
پوسته چندین فرمان ارایه میکند که ما میتوانیم برای کنترل جریانِ اجرا در برنامه خود به کار ببریم. در این درس، ما به موارد زیر نگاه خواهیم نمود:
اولین فرمانی که بررسی خواهیم کرد if است. فرمان if در ظاهر تا اندازهای ساده است، بر اساس
if commands; then commands [elif commands; then commands...] [else commands] fi
که در آن
فرمانها (شامل اسکریپتها و توابعی که ما مینویسیم) هنگامی که خاتمه مییابند، کمیتی به سیستم صادر میکنند که یک وضعیت خروج نامیده میشود. این کمیت، که یک عدد صحیح در محدوده 0 تا 255 است نشاندهنده موفقیت یا شکست اجرای فرمان است. مطابق قرارداد، مقدار صفر بیانگر موفقیت و هر مقدار دیگری نشان دهنده شکست است. پوسته پارامتری فراهم میکند که ما میتوانیم برای بازپرسی وضعیت خروج به کار ببریم. در اینجا آن را در عمل مشاهده میکنیم:
در این مثال، ما فرمان ls را دوبار اجرا میکنیم. دفعه اول، فرمان موفقیتآمیز اجرا میگردد. اگر ما مقدار پارامتر $? را نمایش بدهیم، مشاهده میکنیم که صفر است. فرمان ls را نوبت دوم اجرا میکنیم، یک خطا تولید میکند و دوباره پارامتر $? را بازپرسی میکنیم. این دفعه محتوی 2 است، نشاندهنده آن که فرمان با یک خطا مواجه گردیده است. بعضی فرمانها مقادیرِ وضعیتِ خروجِ متفاوتی به منظورِ میسر کردن عیبشناسی خطاها به کار میبرند، در حالیکه بسیاری از فرمانها وقتی ناموفق میشوند به سادگی با یک مقدار 1 خارج میگردند. صفحههای man اغلب بخشی با عنوان «وضعیت خروج» در توضیح این که کدام کُدها استفاده میشوند ضمیمه میکنند. در هر صورت صفر همیشه بیانگر موفقیت است.
پوسته دو فرمان به شدت سادهِ داخلی فراهم میکند که کاری انجام نمیدهند غیر از اینکه به یک وضعیت خروج صفر یا یک منتهی میشوند. فرمان true همیشه به طور موفقیتآمیز اجرا میگردد و فرمان false همواره به طور ناموفق اجرا میشود:
ما میتوانیم از این فرمانها برای مشاهده آنکه جمله if چطور کار میکند استفاده نماییم. آنچه جمله if واقعاً انجام میدهد ارزیابی موفقیت یا شکست فرمانها میباشد:
فرمان echo "It's true." موقعی اجرا میگردد که فرمان بعد از if به طور موفق اجرا میشود، و هنگامی که اجرای فرمان بعد از if موفقیتآمیز نیست اجرا نمیگردد.
اکثر اوقات فرمان test با فرمان if برای انجام دادن داوریهای صحیح-غلط به کار میرود. فرمانی غیر عادی است از این حیث که دارای دو شکل دستوری متفاوت است:
# شکل اول testexpression # شکل دوم [expression ]
فرمان test به طور ساده کار میکند. اگر عبارت داده شده صحیح باشد، test با وضعیت خروج صفر خارج میشود، در غیر اینصورت با یک وضعیت 1 خارج میگردد.
ویژگی پاکیزه test در تنوع عبارتهایی است که شما میتوانید تولید کنید. این هم یک مثال:
if [ -f .bash_profile ]; then echo "You have a .bash_profile. Things are fine." else echo "Yikes! You have no .bash_profile!" fi
در این مثال، ما عبارت " -f .bash_profile " را به کار میبریم. این عبارت میپرسد، «آیا
این هم یک فهرست نیمه کامل از شرایطی که test میتواند ارزیابی نماید. چون test یک builtin پوسته است، از"help test" برای دیدن فهرست کامل استفاده نمایید.
عبارت | توضیح |
---|---|
-d |
در صورتیکه |
-e |
اگر |
-f |
اگر |
-L |
اگر |
-r |
اگر |
-w |
صحیح در صورتیکه |
-x |
اگر |
اگر |
|
صحیح اگر |
|
-z |
در صورتی صحیح است که |
-n |
صحیح اگر |
اگر |
|
اگر |
قبل از اینکه پیش برویم، من میخواهم باقیمانده مثال بالا را شرح بدهم، چون ایدههای با اهمیتتری را هم آشکار میسازد.
در سطر نخست از اسکریپت، فرمان if را میبینیم که به وسیله فرمان test ادامه یافته، و با یک semicolon دنبال میگردد، و سرانجام کلمه then. من استفاده از [
کاراکتر
[me@linuxbox me]$ clear; ls
صفحه را پاک کرده و فرمان ls را اجرا خواهد نمود.
من از semicolon استفاده میکنم چون به من اجازه میدهد کلمه then را در همان سطر فرمان if قرار بدهم، زیرا من گمان میکنم به این ترتیب برای خواندن آسانتر است.
در سطر دوم، دوست قدیمی ما echo حضور دارد. تنها مورد قابل توجه در این سطر تو گذاری است. دوباره برای سودمندی خوانایی، توگذاری تمام قطعه کُد شرطی، یعنی هر کدی که تنها در صورتی اجرا میگردد که شرایط معینی تحقق یابد، قراردادی است. پوسته به این مورد نیاز ندارد، این کار خواندن کد را آسان میکند.
به بیان دیگر، ما میتوانستیم به صورت زیر بنویسیم و همان نتایج را به دست میآوریم:
# شکل جایگزین if [ -f .bash_profile ] then echo "You have a .bash_profile. Things are fine." else echo "Yikes! You have no .bash_profile!" fi # یک شکل جایگزین دیگر if [ -f .bash_profile ] then echo "You have a .bash_profile. Things are fine." else echo "Yikes! You have no .bash_profile!" fi
برای اینکه نویسندگان اسکریپت خوبی باشیم، ما باید وضعیت خروج را برای موقعی که اسکریپت تمام میشود تنظیم کنیم. برای انجام این کار، فرمان exit را به کار میبریم. فرمان exit باعث میشود بدون واسطه خاتمه یافته و وضعیت خروج را به هر مقدار ارایه شده به عنوان شناسهاش تنظیم نماید. برای مثال:
exit 0
اسکریپت شما خارج میشود و وضعیت خروج را به صفر (موفقیت) تنظیم میکند، در حالیکه با
exit 1
اسکریپت شما خارج میشود و وضعیت خروج را به 1 (شکست) تنظیم میکند.
وقتی آخرین بار اسکریپت خود را ترک کردیم، نیاز داشتیم که با مزایای کاربر ارشد اجرا گردد. چنین است زیرا تابع home_space به بررسی کردن اندازه دایرکتوری خانگی هر کاربر احتیاج دارد، و تنها کاربر ارشد اجازه انجام آن را دارد.
اما اگر یک کاربر عادی اسکریپت ما را اجرا کند چه رخ میدهد؟ مقدار زیادی پیغام خطاهای بد ریخت تولید میکند. اگر میتوانستیم چیزی در اسکریپت قرار بدهیم که وقتی کاربر معمولی تلاش در اجرای آن نماید متوقف شود چطور؟
فرمان id میتواند به ما بگوید چه کسی کاربر جاری است. موقعی که با گزینه
[me@linuxbox me]$ id -u
501
[me@linuxbox me]$ su
Password:
[root@linuxbox me]# id -u
0
اگر کاربر ارشد id -u را اجرا کند، فرمان "0" را بیرون میدهد. این واقعیت میتواند اساس بررسی ما قرار گیرد:
if [ $(id -u) = "0" ]; then echo "superuser" fi
در این مثال، در صورتیکه خروجی فرمان id -u معادل رشته "0" باشد، آنوقت رشته "superuser" چاپ میشود.
در حالیکه اگر کاربر superuser باشد این کد تشخیص خواهد داد، این هنوز به طور واقعی مشکل را رفع نمیکند. ما میخواهیم در صورتیکه کاربر جاری کاربر ارشد نباشدتوقف شود، بنابراین کدی مانند این مینویسیم:
if [ $(id -u) != "0" ]; then echo "You must be the superuser to run this script" >&2 exit 1 fi
با این کد، اگر خروجی فرمان id -u معادل با "0" نباشد، آنوقت اسکریپت یک پیغام خطای وصفی چاپ کرده، خارج میشود، و برای نشان دادن آنکه اسکریپت به طور ناموفق اجرا گردیده وضعیت خروج را به 1 تنظیم میکند.
به
میتوانستیم این روال را نزدیک ابتدای اسکریپتمان قرار بدهیم به این ترتیب شانس تشخیص دادن خطای احتمالی قبل از پیش رفتن موارد را دارد، اما به منظور اجرای این اسکریپت به عنوان یک کاربر معمولی، همان ایده را به کار میبریم و در عوض تابع home_space را برای تست امتیازهای مناسب به این صورت ویرایش میکنیم:
function home_space { # فقط کاربر ارشد میتواند این اطلاعات را به دست بیاورد if [ "$(id -u)" = "0" ]; then echo "<h2>Home directory space by user</h2>" echo "<pre>" echo "Bytes Directory" du -s /home/* | sort -nr echo "</pre>" fi } # end of home_space
به این طریق، اگر یک کاربر معمولی اسکریپت را اجرا کند، کد دردسر آفرین به جای آنکه اجرا شود، چشم پوشی میگردد و مشکل رفع خواهد شد.