برنامهنویسی پوسته یک جعبه گرامافون دهه 1950 است . . . --Larry Wall |
در سادهترین حالت، یک اسکریپت چیزی بیش از یک لیست فرمانهای ذخیره شده در یک فایل نیست. این فایل هر بار که فراخوانی میگردد حداقل زحمت تایپ مجدد آن گروه بخصوص از فرمانها را صرفهجویی میکند.
مثال 2-1. cleanup: یک اسکریپت برای پاکسازی فایل ثبت رخداد در /var/log
# # cd /var/log cat /dev/null > messages cat /dev/null > wtmp echo "Log files cleaned up."
در اینجا هیچ مورد غیر عادی وجود ندارد، فقط مجموعهای از فرمانها هستند که به آسانی میتوانستند یک به یک از طریق خط فرمان روی کنسول یا یک پنجره ترمینال فراخوانی شده باشند. امتیاز قرار دادن فرمانها در یک اسکریپت، در برطرف نمودن لزوم دوباره تایپ کردن آنها است. اسکریپت یک برنامه -- یک ابزار -- میشود و به آسانی میتواند برای یک کاربرد خاص ویرایش یا سفارشی بشود.
مثال 2-2. cleanup: یک اسکریپت clean-up بهبودیافته
#!/bin/bash # # # # # LOG_DIR=/var/log # cd $LOG_DIR cat /dev/null > messages cat /dev/null > wtmp echo "Logs cleaned up." exit #شیوه صحیح و بایسته خروج از یک اسکریپت. یک «exit» ساده #(بدون پارامتر) وضعیت خروج فرمان قبلی را برگشت میدهد.
اکنون آن کد مانند یک اسکریپت واقعی به نظر میرسد. اما میتوانیم حتی پیشتر برویم . . .
مثال 2-3. cleanup: یک نگارش ارتقا یافته و تعمیم داده شده از اسکریپتهای فوق.
#!/bin/bash # #هشدار: # # # LOG_DIR=/var/log ROOT_UID=0 #فقط کاربرانی با $UID برابر با 0 دارای امتیازات root هستند. LINES=50 # E_XCD=86 # E_NOTROOT=87 # # if [ "$UID" -ne "$ROOT_UID" ] then echo "Must be root to run this script." exit $E_NOTROOT fi if [ -n "$1" ] # then lines=$1 else lines=$LINES # fi # #+ #+ # # # # # # # # # # # cd $LOG_DIR if [ `pwd` != "$LOG_DIR" ] # # then echo "Can't change to $LOG_DIR." exit $E_XCD fi # # # # # # # tail -n $lines messages > mesg.temp # mv mesg.temp messages # # #* cat /dev/null > wtmp # echo "Log files cleaned up." # #+ exit 0 #
چون ممکن است شما مایل به پاک کردن تمام log سیستم نباشید، این نگارش از اسکریپت آخرین بخش پیغام فایل log را دستنخورده نگاه میدارد. شما به طور دائم روشهای میزانسازی دقیق اسکریپتهای نوشته شده قبلی به منظور افزایش کارایی آنها را کشف خواهید نمود.
شبانگ(#!) [1] در ابتدای یک اسکریپت به سیستم شما میگوید که این فایل یک مجموعه از فرمانها برای تغذیه شدن به مفسر فرمان اشاره شده است. #! در حقیقت یک magic number دو بایتی است[2] ، یک علامتگذار که نوع فایل، یا در این مورد یک اسکریپت پوسته قابل اجرا را مشخص میکند (برای جزییات بیشتر در باره این مبحث جذاب، دستور man magic را تایپ کنید). بلافاصله به دنبال sha-bang یک نام مسیر است. این نام، بیانگر مسیر برنامهای است که فرمانهای داخل اسکریپت را تفسیر میکند، خواه یک پوسته، یک زبان برنامهنویسی، یا یک برنامه سودمند باشد. سپس این مفسر فرمان با شروع از بالا (سطر بعداز sha-bang)، و صرفنظر کردن از توضیحات، فرمانهای داخل اسکریپت را اجرا میکند. [3]
#!/bin/sh #!/bin/bash #!/usr/bin/perl #!/usr/bin/tcl #!/bin/sed -f #!/bin/awk -f
هر یک از سطرهای سرآیند اسکریپت در بالا یک مفسر فرمان متفاوت را فرا میخواند، خواه /bin/sh پوسته پیشفرض (و bash در یک سیستم لینوکس) باشد یا غیر از آن[4]. استفاده از #!/bin/sh، که پوسته Bourne پیشفرض در اکثر گونههای تجاری یونیکس است، اسکریپت را قابل حمل به ماشینهای غیر لینوکس میکند، اگر چه شما ویژگیهای مختص Bash را از دست میدهید. اما اسکریپت مطابق با استاندارد sh POSIX
توجه نمایید که مسیر تعیین شده در «sha-bang» باید صحیح باشد، در غیر اینصورت یک پیغام خطا -- به طور معمول «Command not found.» -- تنها نتیجه اجرای اسکریپت خواهد بود.[6]
در صورتیکه اسکریپت فقط متشکل از یک مجموعه فرمانهای عمومی سیستم بدون کاربرد دستورات داخلی پوسته باشد، #! میتواند از قلم انداخته شود. مثال دوم بالا، به #! ابتدایی نیاز دارد، چون سطر تخصیص متغیر lines=50 از یک ساختار مخصوص پوسته استفاده میکند.[7] یکبار دیگر توجه نمایید که #!/bin/sh مفسر پوسته پیشفرض را که در ماشینهای لینوکس /bin/bash است فراخوانی میکند.
این آموزش، رویکرد پیمانهای برای ساختن یک اسکریپت را تشویق میکند. قطعات خردهریز کد را که شاید برای اسکریپتهای بعدی مفید باشند یادداشت کرده جمعآوری نمایید. سرانجام واقعاً یک کتابخانه وسیع از روالهای خیلی خوب خواهید ساخت. به عنوان یک مثال، اسکریپت پایین بررسی میکند که آیا اسکریپت باتعداد پارامترهای صحیح فراخوانی گردیده است.
E_WRONG_ARGS=85 script_parameters="-a -h -m -z" # if [ $# -ne $Number_of_expected_args ] then echo "Usage: `basename $0` $script_parameters" # exit $E_WRONG_ARGS fi شما بارها اسکریپتی خواهید نوشت که یک وظیفه بخصوص را انجام میدهد. اسکریپت اول این فصل یک نمونه آن است. بعدها ممکن است پیش بیاید که شما اسکریپت را برای انجام سایر وظایف مشابه تعمیم بدهید. تعویض ثابتهای لفظی ("hard-wired") با متغیرها، اقدامی در این جهت است، همانطور که جایگزینی قطعات کد تکرارشوند به وسیله توابع چنین است. |
[1] | در نوشتهها بیشتر به صورت she-bang یا sh-bang دیده شده. این اصطلاح از الحاق نشانههای sharp (#) و bang (!) حاصل میشود. |
[2] | بعضی از گرایشهای یونیکس (آنها که مبتنی بر BSD 4.2 هستند) به طوری که ادعا گردیده، یک magic number چهار بایتی میگیرند، که نیازمند یک جای خالی بعد از ! است -- #! /bin/sh. به قول Sven Mascheck این احتمالاً یک افسانه است. |
[3] | سطر #! در یک اسکریپت پوسته اولین چیزی خواهد بود که مفسر فرمان (sh یا bash) میبیند. چون این سطر با یک # شروع میشود، وقتی سرانجام مفسرفرمان اسکریپت را اجرا میکند به طور صحیح به عنوان یک توضیح تفسیر خواهد گردید. این سطر قبلاً به هدفش - فراخوانی مفسر فرمان - خدمت کرده است. در واقع، اگر اسکریپت شامل یک سطر اضافی #! باشد، آنوقت bash آن را به عنوان یک توضیح تفسیر خواهد نمود. #!/bin/bash echo "Part 1 of script." a=1 #!/bin/bash # echo "Part 2 of script." echo $a # |
[4] | این مورد، برخی ترفندهای جالب را میسر میسازد. #!/bin/rm # # WHATEVER=85 echo "This line will never print (betcha!)." exit $WHATEVER # # # همچنین، شروع یک فایل README با یک #!/bin/more و قابل اجرا کردن آن را امتحان کنید. نتیجه یک فایل مستندسازی خود فهرست کننده است. (یک here document با کاربرد cat احتمالاً جایگزین مناسبتری است -- مثال 19-3 را ببینید). |
[5] | PortableOperating System Interface، یک کوشش استانداردسازی سیستمعاملهای UNIX-مبنا میباشد. مشخصات POSIX در سایت Open Group لیست گردیده است. |
[6] | برای پرهیز از این احتمال، یک اسکریپت میتواند با سطر sha-bang به صورت #!/bin/env bash شروع بشود. این مورد ممکن است در آن ماشینهای یونیکس که bash در آنها در دایرکتوری /bin قرار ندارد مفید باشد. |
[7] | اگر Bash پوسته پیشفرض شما باشد، آنوقت #! در ابتدای یک اسکریپت ضروری نیست. به هرحال در صورت راهاندازی اسکریپت از یک پوسته متفاوت مانند tcsh، آنوقت شما به #! نیاز خواهید داشت. |