بررسی و انشعاب

فصل ‎11‎- حلقه‌ها و انشعاب‌ها

‎11.4‎- بررسی و انشعاب

ساختارهای case و select از نظر تکنیکی حلقه نیستند، چون آنها اجرای یک قطعه کد را تکرار نمی‌کنند. اگر چه، آنها نیز جریان برنامه را بر حسب شرایط ابتدا یا انتهای قطعه کد هدایت می‌کنند.

کنترل جریان برنامه در یک قطعه کد

‎case (in) / esac‎

ساختار case در اسکریپت‌نویسی پوسته قابل قیاس با switch در ‎C/C++‎ است. این ساختار بر اساس وضعیت بررسی‌ها، انشعاب به یکی از چند قطعه کد را اجازه می‌دهد. به عنوان یک نوع میانبر برای چندین جمله ‎if/then/else‎ خدمت می‌کند و ابزار مناسبی برای ایجاد منوها است.

case "$variable" in

"$condition1" )
command...
;;

"$condition2" )
command...
;;


esac

  • نقل‌قول متغیرها الزامی نیست، چون تفکیک کلمه صورت نمی‌گیرد.

  • هر سطر تست با یک پرانتز سمت راست ‎)‎ خاتمه می‌یابد. ‎[1]‎

  • هر بلوک شرط با یک سمی‌کالن دوگانه ;; خاتمه می‌یابد.

  • اگر شرط بررسی‌ها صحیح باشد، آنوقت فرمانهای مربوطه اجرا می‌گردند و بلوک case خاتمه می‌یابد.

  • کل بلوک case با یک esac ( املای معکوس case) پایان می‌پذیرد.


مثال ‎11-25‎. کاربرد case

#!/bin/bash
#

echo; echo "Hit a key, then hit return."
read Keypress

case "$Keypress" in
  [[:lower:]]   ) echo "Lowercase letter";;
  [[:upper:]]   ) echo "Uppercase letter";;
  [0-9]         ) echo "Digit";;
  *             ) echo "Punctuation, whitespace, or other";;
esac      # محدوده کاراکترها در [براکت‌ها]، یا محدوده‌های
          #+POSIX‎ در ‎[[‎ براکت‌های دوتایی را اجازه می‌دهد.

#
#+    ‎[a-z]‎ و ‎[A-Z]‎ بود. این دیگر در برخی مناطق و/یا توزیع‌های لینوکس 
#                               کار نمی‌کند. ‎POSIX‎ بیشتر قابل حمل است.
#                با نشکر از ‎Frank Wang‎ برای اشاره نمودن به این مورد.

#                             
#                            
#
#
#+               کلید گزارش  بدهد، و فقط وقتی ‎"X"‎ زده می‌شود، خاتمه یابد.
#                     اشاره: همه چیز را درون یک حلقه ‎"while"‎ قرار بدهید.

exit 0

مثال ‎11-26‎. ایجاد منوها با استفاده از case

#!/bin/bash

#     

clear #

echo "          Contact List"
echo "          ------- ----"
echo "Choose one of the following persons:" 
echo
echo "[E]vans, Roland"
echo "[J]ones, Mildred"
echo "[S]mith, Julie"
echo "[Z]ane, Morris"
echo

read person

case "$person" in
#

  "E" | "e" )
  #
  echo
  echo "Roland Evans"
  echo "4321 Flash Dr."
  echo "Hardscrabble, CO 80753"
  echo "(303) 734-9874"
  echo "(303) 734-9892 fax"
  echo "revans@zzy.net"
  echo "Business partner & old friend"
  ;;
#

  "J" | "j" )
  echo
  echo "Mildred Jones"
  echo "249 E. 7th St., Apt. 19"
  echo "New York, NY 10009"
  echo "(212) 533-2814"
  echo "(212) 533-9972 fax"
  echo "milliej@loisaida.com"
  echo "Ex-girlfriend"
  echo "Birthday: Feb. 11"
  ;;

# بعداً  اطلاعات ‎Smith و ‎Zane‎ را اضافه کنید.

          * )
   #  
   #
   echo
   echo "Not yet in database."
  ;;

esac

echo

#                   
#                  
#
#+

exit 0

یک استفاده هوشمندانه استثنایی case به بررسی پارامترهای سطر فرمان مربوط می‌شود.

#! /bin/bash

case "$1" in
  "") echo "Usage: ${0##*/} <filename>"; exit $E_PARAM;;
#      
#  توجه کنید که ‎${0##*/}‎ جایگزینی پارامتر ‎${var##pattern}‎ است.
#                                          نتیجه خالص ‎$0‎ است.
  -*) FILENAME=./$1;;
# اگر نام فایل داده شده به عنوان ‎($1)‎ با یک خط تیره شروع شود، آن
#+  را با ‎./$1‎ تعویض کند طوری که فرمانها دیگر آن را به عنوان 
#+                                    

  * ) FILENAME=$1;;
#                                     در غیر اینصورت، ‎$1‎ باشد.
esac

این هم یک مثال قابل فهم‌تر در مورد مدیریت پارامتر خط فرمان:

#! /bin/bash


while [ $# -gt 0 ]; do               #        
  case "$1" in
    -d|--debug)
                                     #  پارامتر ‎"-d"‎ یا ‎"--debug"‎ است؟
              DEBUG=1
              ;;
    -c|--conf)
              CONFFILE="$2"
              shift
              if [ ! -f $CONFFILE ]; then
                echo "Error: Supplied file doesn't exist!"
                exit $E_CONFFILE     #        
              fi
              ;;
  esac
  shift                              # 
done

    #   از اسکریپت "Log2Rot" بسته ‎"rottlog"‎ متعلق به ‎Stefano Falsetto‎
    #                 

مثال ‎11-27‎. کاربرد جایگزینی فرمان برای تولید متغیر case

#!/bin/bash
# ‎case-cmd.sh‎: استفاده از جایگزینی فرمان در تولید یک متغیر ‎"case"‎.

case $( arch ) in   # ‎$( arch )‎ معماری کامپیوتر را برگشت می‌دهد.
                    # معادل با ‎'uname -m'‎ 
  i386 ) echo "80386-based machine";;
  i486 ) echo "80486-based machine";;
  i586 ) echo "Pentium-based machine";;
  i686 ) echo "Pentium2+-based machine";;
  *    ) echo "Other type of machine";;
esac

exit 0

یک ساختار case می‌تواند رشته‌ها را بواسطه الگوهای globbing فیلتر کند.

مثال ‎11-28‎. انطباق رشته ساده

#!/bin/bash
# ‎match-string.sh‎: انطباق رشته ساده
#          کاربرد یک ساختار ‎'case'‎.

match_string ()
{ # Exact string match.
  MATCH=0
  E_NOMATCH=90
  PARAMS=2     #
  E_BAD_PARAMS=91

  [ $# -eq $PARAMS ] || return $E_BAD_PARAMS

  case "$1" in
  "$2") return $MATCH;;
  *   ) return $E_NOMATCH;;
  esac

}  


a=one
b=two
c=three
d=two


match_string $a     #
echo $?             #

match_string $a $b  #
echo $?             #

match_string $b $d  #
echo $?             #


exit 0		    

مثال ‎11-29‎. کنترل برای ورودی الفبایی

#!/bin/bash
#        ‎isalpha.sh‎: کاربرد ساختار ‎"case"‎ برای فیلتر کردن یک رشته.

SUCCESS=0
FAILURE=1   #	   	        ‎FAILURE=-1‎ بود اما Bash دیگر برگشت
            #+     		 

isalpha ()  #
{
if [ -z "$1" ]          	     #  آیا شناسه‌ای ارایه نشده است؟
then
  return $FAILURE
fi

case "$1" in
  [a-zA-Z]*) return $SUCCESS;;        #      با یک حرف شروع می‌شود؟
  *        ) return $FAILURE;;
esac
}                #    این را با تابع ‎"isalpha ()"‎ در ‎C‎ مقایسه کنید.


isalpha2 ()      #         بررسی می‌کند آیا «تمام رشته» الفبایی است.
{
  [ $# -eq 1 ] || return $FAILURE

  case $1 in
  *[!a-zA-Z]*|"") return $FAILURE;;
               *) return $SUCCESS;;
  esac
}

isdigit ()       #           بررسی می کند آیا «تمام رشته» عددی است.
{                #       به بیان دیگر، برای متغیر صحیح بررسی می‌کند.
  [ $# -eq 1 ] || return $FAILURE

  case $1 in
    *[!0-9]*|"") return $FAILURE;;
              *) return $SUCCESS;;
  esac
}



check_var ()    #  وابسته به تابع ‎isalpha ()‎
{
if isalpha "$@"
then
  echo "\"$*\" begins with an alpha character."
  if isalpha2 "$@"
  then          #اگر کاراکتر اول الفبایی نباشد، این بررسی لزومی ندارد.
    echo "\"$*\" contains only alpha characters."
  else
    echo "\"$*\" contains at least one non-alpha character."
  fi  
else
  echo "\"$*\" begins with a non-alpha character."
                # همچنین اگر شناسه‌ای داده نشده باشد، غیر الفبایی است.
fi

echo

}

digit_check ()  #  وابسته به تابع ‎isdigit ()‎
{
if isdigit "$@"
then
  echo "\"$*\" contains only digits [0 - 9]."
else
  echo "\"$*\" has at least one non-digit character."
fi

echo

}

a=23skidoo
b=H3llo
c=-What?
d=What?
e=$(echo $b)    #  جایگزینی فرمان.
f=AbcDef
g=27234
h=27a34
i=27.34

check_var $a
check_var $b
check_var $c
check_var $d
check_var $e
check_var $f
check_var       #  شناسه‌ای داده نشده، بنابراین چه می‌شود؟
#
digit_check $g
digit_check $h
digit_check $i


exit 0          #  اسکریپت توسط ‎S.C.‎ بهینه شده است.

#                       
#                      
# یک تابع ‎isfloat ()‎ بنویسید که اعداد اعشاری را بررسی کند.
#   اشاره: تابع رونوشت ‎isdigit ()‎ است اما یک تست برای بررسی 
#+                         نقطه اعشار اختیاری اضافه می‌شود.

select

ساختار select، که از پوسته ‎Korn‎ اقتباس گردیده است، ابزار دیگری برای ساختن منوها است.

selectvariable [in list]
do
command...
 break
done

این ساختار، برای وارد کردن یکی از انتخاب‌های نمایش داده شده در ‎variable list اعلانی به کاربر ارایه می‌دهد‎. توجه کنید که select به طور پیش‌فرض اعلان ‎$PS3‎ ‏(‎#?‎) را به کار می‌برد، اما این اعلان می‌تواند تغییر داده شود.

مثال ‎11-30‎. تولید منوها با استفاده از select

#!/bin/bash

PS3='Choose your favorite vegetable: ' #         
                                       #   در غیر اینصورت پیش‌فرض ‎#?‎

echo

select vegetable in "beans" "carrots" "potatoes" "onions" "rutabagas"
do
  echo
  echo "Your favorite veggie is $vegetable."
  echo "Yuck!"
  echo
  break  #  اگر در اینجا ‎'break'‎ نباشد چه اتفاقی رخ می‌دهد؟
done

exit

#                       
#                      
#  
#+             تعیین نشده در جمله ‎"select"‎ اصلاح کنید.
#  برای مثال، اگر کاربر ‎"peas"‎ را وارد نماید، اسکریپت
#+        پاسخ بدهد ‎"Sorry. That is not on the menu."‎

اگر ‎in list‎ ذکر نگردد، آنوقت select لیست شناسه‌های سطر فرمان ‎($@)‎ عبور داده شده به اسکریپت یا تابع محتوی ساختار select را به کار می‌برد.

این مورد را با رفتار ساختار ‎for variable [in list]‎ که ‎in list‎ در آن از قلم افتاده، مقایسه کنید.

مثال ‎11-31‎. تولید منوها با استفاده از select در یک تابع

#!/bin/bash

PS3='Choose your favorite vegetable: '

echo

choice_of()
{
select vegetable
# ‎[in list]‎ ذکر نشده، پس ‎'select'‎ شناسه‌های داده شده به تابع را استفاده می‌کند.
do
  echo
  echo "Your favorite veggie is $vegetable."
  echo "Yuck!"
  echo
  break
done
}

choice_of beans rice carrots radishes rutabaga spinach
#
#	             تحویل داده شده به تابع ‎choice_of()‎

exit 0

همچنین مثال ‎37-3‎ را ببینید.

یادداشت‌ها

[1]

برای چیدمانی با ظاهر شکیل‌تر، سطرهای انطباق الگو می‌توانند با یک پرانتز سمت چپ -‎(‎ - نیز شروع بشوند.

case $( arch ) in   # ‎$( arch )‎ معماری ماشین را برگشت می‌دهد.
  ( i386 ) echo "80386-based machine";;
#
  ( i486 ) echo "80486-based machine";;
  ( i586 ) echo "Pentium-based machine";;
  ( i686 ) echo "Pentium2+-based machine";;
  (    * ) echo "Other type of machine";;
esac