شروع با یک شبانگ

فصل 2: شروع با یک Sha-Bang

 

برنامه‌نویسی پوسته یک جعبه گرامافون دهه 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‎[5]‎ خواهد بود.

توجه نمایید که مسیر تعیین شده در «sha-bang» باید صحیح باشد، در غیر اینصورت یک پیغام خطا -- به طور معمول ‎«Command not found.»‎ -- تنها نتیجه اجرای اسکریپت خواهد بود.‎[6]‎

در صورتیکه اسکریپت فقط متشکل از یک مجموعه فرمان‌های عمومی سیستم بدون کاربرد دستورات داخلی پوسته باشد، ‎#!‎ می‌تواند از قلم انداخته شود. مثال دوم بالا، به ‎#!‎ ابتدایی نیاز دارد، چون سطر تخصیص متغیر ‎lines=50‎ از یک ساختار مخصوص پوسته استفاده می‌کند.‎[7]‎ یک‌بار دیگر توجه نمایید که ‎#!/bin/sh‎ مفسر پوسته پیش‌فرض را که در ماشین‌های لینوکس ‎/bin/bash‎ است فراخوانی می‌کند.

Tip

این آموزش، رویکرد پیمانه‌ای برای ساختن یک اسکریپت را تشویق می‌کند. قطعات خرده‌ریز کد را که شاید برای اسکریپت‌های بعدی مفید باشند یادداشت کرده جمع‌آوری نمایید. سرانجام واقعاً یک کتابخانه وسیع از روال‌های خیلی خوب خواهید ساخت. به عنوان یک مثال، اسکریپت پایین بررسی می‌کند که آیا اسکریپت باتعداد پارامترهای صحیح فراخوانی گردیده است.

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، آنوقت شما به ‎#!‎ نیاز خواهید داشت.