فصل 8. عملکردها و مباحث مربوط

8.1- عملگرها

اختصاص دادن

تخصیص متغیر

ارزش‌گذاری یا تغییر محتوای یک متغیر

=

عملگر تخصیص همه منظوره، که برای هر دو تخصیص رشته‌ای و حسابی عمل می‌کند.

var=27
category=minerals  #  .مجاز نیست ‎"="‎ هیچ فاصله‌ای در طرفین‎ 

Caution

عملگر "=" تخصیص را با عملگر = تست اشتباه نکنید.

#  به عنوان یک عملگر تست ‎=‎  

if [ "$string1" = "$string2" ]
then
   command
fi

#   برای پیش‌گیری از یک پیغام خطا در صورت تهی بودن یکی از متغیرها،
#+ قابل اطمینان‌تر است ‎if [ "X$string1" = "X$string2" ]‎ استفاده از
#             (کاراکترهای ‎"X"‎ پیشوند شده، یکدیگر را خنثی می‌کنند.)

عملگرهای حسابی

+

جمع

-

تفریق

*

ضرب

/

تقسیم

**

توان

#  .را معرفی کرده است ‎"**"‎ عملگر به توان رساندن ‎2.02‎ در نگارش ‎Bash‎ 

let "z=5**3"    #  5 * 5 * 5
echo "z = $z"   #  z = 125

%

modulo‏، یا mod ( باقیمانده یک عملیات تقسیم صحیح را برگشت می‌دهد)

bash$ expr 5 % 3
2
‎5/3 = 1‎ است با باقیمانده ‎2‎

این عملگر در تولید اعداد داخل یک محدوده خاص ( مثال ‎9-11‎ و مثال ‎9-15‎ را ببینید) و قالب‌بندی خروجی برنامه ( مثال ‎27-16‎ و مثال ‎A-6‎ را ببینید) سودمند واقع می‌شود. حتی می‌تواند برای تولید اعداد اول به کار برود (مثال ‎A-15‎ را ببینید). Modulo به طور شگفت‌انگیزی در دستورالعمل‌های عددی ظاهر می‌شود.

مثال ‎8-1‎. بزرگترین مقسوم علیه مشترک

#!/bin/bash
#  gcd.sh:     بزرگترین مقسوم‌علیه مشترک‎
#       را به کار می‌برد ‎Euclid‎ الگوریتم‎

# بزرگترین مقسوم‌علیه مشترک دو عدد صحیح، بزرگترین عدد صحیحی ‎(gcd)‎
#+    .است که هر دو عدد به آن تقسیم شده و باقیمانده نخواهند داشت‎
‎
#  از تقسیم متوالی استفاده می‌کند ‎Euclid‎ الگوریتم‎
# در هر مرحله از تقسیم، تبدیل‌های زیر انجام می‌شود‎
#+                         مقسوم ‎<---‎  مقسوم‌علیه‎
#+                    مقسوم‌علیه  ‎<---‎  باقیمانده‎
#+                تا زمانی که باقیمانده صفر بشود‎
#    مقسوم آخرین مرحله، بزرگترین مقسوم‌علیه مشترک خواهد بود‎
#
#   ‎Jimm Loy‎ سایت ‎Euclid‎ برای یک گفتمان بسیار خوب در مورد الگوریتم ‎
#+     .را ببینید ‎http://www.jimloy.com/number/euclids.htm‎ به آدرس ‎


# ------------------------------------------------------
# کنترل شناسه‌ها‎
ARGS=2
E_BADARGS=85

if [ $# -ne "$ARGS" ]
then
  echo "Usage: `basename $0` first-number second-number"
  exit $E_BADARGS
fi
# ------------------------------------------------------


gcd ()
{

  dividend=$1             # تخصیص اختیاری، اهمیت ندارد که‎
  divisor=$2              #.کدام یک از دو عدد بزرگتر باشد‎
                          #                 چرا مهم نیست؟‎

  remainder=1             #  اگر یک متغیر ارزش‌گذاری نشده در داخل عبارت‎
                          #+ .به کار برود، به یک پیغام خطا منجر می‌گردد‎

  until [ "$remainder" -eq 0 ]
  do    #  ‎^^^^^^^^^^‎             !باید قبلاً مقدار دهی شده باشد‎
    let "remainder = $dividend % $divisor"
    dividend=$divisor     # حال با دوعدد کوچکتر تکرار خواهد شد
    divisor=$remainder
  done                    #                    ‎Euclid‎ الگوریتم‎

}                # بزرگترین مقوم‌علیه مشترک است ‎$dividend‎ آخرین


gcd $1 $2

echo; echo "GCD of $1 and $2 = $dividend"; echo


#                   :تمرین‎
# ---------------------------------------
#   شناسه‌های خط فرمان را کنترل کنید که عدد صحیح باشند، و در ‎(1‎ 
#+     .غیر اینصورت اسکریپت با یک پیغام خطای مناسب خارج شود‎
# را برای استفاده ازمتغیرهای محلی بازنویسی کنید ‎gcd ()‎ تابع ‎(2‎ 

exit 0
‎+=‎

افزایش-مساوی (افزایش مقدار ثابت به متغیر) ‎[1]‎

‎let "var += 5"‎ به این منجر می‌شود که 5 به var اضافه شود.

‎-=‎

تفریق-مساوی (تفریق مقدار ثابت از متغیر)

‎*=‎

ضرب-مساوی (ضرب مقدار ثابت در متغیر)

‎let "var *= 4"‎ منجر به این می‌گردد که var ضرب در 4 بشود.

‎/=‎

تقسیم-مساوی (تقسیم متغیر بر مقدار ثابت)

‎%=‎

باقیمانده-مساوی (باقیمانده تقسیم متغیر بر مقدار ثابت)

عملگرهای حسابی بیشتر اوقات در یک عبارت expr یا let واقع می‌شوند.

مثال ‎8-2‎. کاربرد عملگرهای حسابی

#!/bin/bash
# روش مختلف ‎10‎ با استفاده از ‎11‎ شمارش تا‎

n=1; echo -n "$n "

let "n = $n + 1"   # .نیز کار می‌کند ‎let "n = n + 1"‎ 
echo -n "$n "


: $((n = $n + 1))
#  سعی در ‎Bash‎ لازم است برای اینکه در غیر اینصورت  ‎":"‎
#+ .به عنوان یک فرمان می‌نماید ‎"$((n = $n + 1))"‎ تفسیر
echo -n "$n "

(( n = n + 1 ))
#    یک جایگزین ساده‌تر برای روش فوق. با تشکر‎
#  .برای روشن کردن این مورد ‎David Lombard‎ از‎
echo -n "$n "

n=$(($n + 1))
echo -n "$n "

: $[ n = $n + 1 ]
#           سعی در ‎Bash‎ لازم است برای اینکه در غیر اینصورت  ‎":"‎
#+          .به عنوان یک فرمان می‌نماید ‎"$[ n = $n + 1 ]"‎ تفسیر
#  .به عنوان یک رشته ارزش‌گذاری شده باشد، کار می‌کند ‎"n"‎ حتی اگر‎
echo -n "$n "

n=$[ $n + 1 ]
#  .به عنوان یک رشته ارزش‌گذاری شده باشد، کار می‌کند ‎"n"‎ حتی اگر‎
#*      .از این ساختار پرهیز کنید، چون منسوخ و غیرقابل حمل است 
#        ‎Stephane Chazelas‎ با تشکر از‎
echo -n "$n "

#        ‎C‎  اکنون برای عملگرهای افزایشی سبکِ
# برای اشاره به این مورد ‎Frank Wang‎ تشکر از‎

let "n++"          # .نیز کار می‌کند ‎let "++n"‎ 
echo -n "$n "

(( n++ ))         #  .نیز کار می‌کند ‎(( ++n ))‎
echo -n "$n "

: $(( n++ ))       # ‎.نیز کار می‌کند ‎: $(( ++n ))‎
echo -n "$n "

: $[ n++ ]         # .نیز کار می‌کند ‎: $[ ++n ]‎ 
echo -n "$n "

echo

exit 0

متغیرهای صحیح در نگارش‌های قدیمی‌تر Bash، اعداد صحیح بلند با علامت ‎(32-bit)‎ در محدوده ‎-2147483648‎ تا ‎2147483647‎ بودند. عملیاتی که متغیری خارج از این محدوده دریافت می‌کرد، یک نتیجه اشتباه‌آمیز ارایه می‌داد.

echo $BASH_VERSION   # 1.14

a=2147483646
echo "a = $a"        # a = 2147483646
let "a+=1"           #  ‎"a"‎ افزایش‎
echo "a = $a"        # a = 2147483647
let "a+=1"           # فراتر از محدودیت ‎"a"‎ افزایش دوباره‎
echo "a = $a"        # a = -2147483648
                     #      ERROR: out of range,
                     # + و آخرین بیت سمت چپ، بیت علامت، تنظیم ‎
                     # + .گردیده است، که نتیجه را منفی می‌کند‎

در نتیجه Bash از نگارش ‎>= 2.05b‎ از اعداد صحیح ۶۴ بیتی پشتیبانی می‌کند.

Caution

Bash حساب ممیز شناور را نمی‌فهمد. با اعداد شامل نقطه اعشار به عنوان رشته رفتار می‌کند.

a=1.5

let "b = $a + 1.3"  # Error.
# t2.sh: let: b = 1.5 + 1.3: syntax error in expression
#                            (error token is ".5 + 1.3")

echo "b = $b"       # b=

در اسکریپت‌هایی که به محاسبات اعشاری یا توابع کتابخانه‌ای ریاضی نیاز دارند از bc استفاده کنید.


عملگرهای بیتی. عملگرهای بیتی به ندرت در اسکریپت‌های پوسته ظهور می کنند. به نظر می‌رسد کاربرد عمده آنها برای دستکاری و بررسی کمیت‌های خوانده شده از پورت‌ها یا سوکت‌ها باشد. «وارونه‌سازی وضعیت بیت‌ها» بیشتر برای زباهای ترجمه شونده، از قبیل C و ‎C++‎ که دسترسی مستقیم به سخت‌افزار سیستم را فراهم می‌کنند مناسب است. به هر حال، ابتکار vladz در به کار بردن عملگرهای بیتی در اسکریپت ‎base64.sh‎ او (مثال ‎A-54‎) را ملاحظه نمایید.

عملگرهای بیتی

‎<<‎

انتقال به چپ بیتی (ضرب در 2 برای هر نقل‌مکان)

‎<<=‎

left-shift-equal

‎let "var <<= 2"‎ موجب می‌گردد var به اندازه 2 بیت به سمت چپ نقل‌مکان کند (ضربدر 4)

‎>>‎

نقل‌مکان بیتی به راست (تقسیم بر 2 برای هر نقل‌مکان)

‎>>=‎

right-shift-equal (برعکس ‎<<=‎ است)

‎&‎

AND بیتی

‎&=‎

‎AND-equal‎ بیتی

|

OR بیتی

‎|=‎

OR-equal بیتی

~

نفی بیتی

^

XOR بیتی

‎^=‎

XOR-equal بیتی

عملگرهای منطقی (boolean)

!

نفی

if [ ! -f $FILENAME ]
then
  ...
&&

و

if [ $condition1 ] && [ $condition2 ]
#     در صورتیکه هر دو ‎if [ $condition1 -a $condition2 ]‎ همچون
#  .صحیح باشند صحیح را برگشت می‌دهد ‎condition2‎ و ‎condition1‎ شرط

if [[ $condition1 && $condition2 ]]        # .این هم کار می‌کند‎
#    .مجاز نیست ‎[ ... ]‎داخل ساختار براکت‌ها ‎&&‎ توجه نمایید که عملگر

&& همچنین نسبت به مضمون می‌تواند در یک and list برای به هم پیوستن فرمان‌ها به کار برود.

||

یا

if [ $condition1 ] || [ $condition2 ]
# در صورتی صحیح را برگشت  ‎if [ $condition1 -o $condition2 ]‎ همچون‎
#      .صحیح باشد ‎condition2‎ یا ‎condition1‎ می‌دهد که یکی از دو شرط ‎

if [[ $condition1 || $condition2 ]]            # این هم کار می‌کند‎
#       .مجاز نیست ‎[ ... ]‎داخل ساختار براکت‌ها ‎||‎ توجه نمایید که عملگر

Bash وضعیت خروج هر جمله متصل شده توسط یک عملگر منطقی را بررسی می‌کند.

مثال ‎8-3‎. بررسی‌های شرط مرکب با استفاده از ‎&&‎ و ‎||‎

#!/bin/bash

a=24
b=47

if [ "$a" -eq 24 ] && [ "$b" -eq 47 ]
then
  echo "Test #1 succeeds."
else
  echo "Test #1 fails."
fi

#    خطا: سطر ‎if [ "$a" -eq 24 && "$b" -eq 47 ]‎ سعی در اجرای
#+   فرمان ‎' [ "$a" -eq 24 '‎‎ نموده و در پیدا کردن جفت ‎']'‎ آن
#                                        باشکست مواجه می‌گردد.
# کار می‌کند. براکت‌های  ‎if [[ $a -eq 24 && $b -eq 24 ]] :‎توجه‎
#       .انعطاف‌پذیرتر از براکت‌های منفرد هستند ‎if-test‎ دوگانه ‎
#       (معنی ‎"&&"‎ در سطر ۱۷ متفاوت با معنی آن در سطر ۶ است.)
#  .برای اشاره کردن به این مطلب ‎Stephane Chazelas‎ با تشکر از‎


if [ "$a" -eq 98 ] || [ "$b" -eq 47 ]
then
  echo "Test #2 succeeds."
else
  echo "Test #2 fails."
fi


#  .یک بررسی شرط مرکب جایگزین فراهم می‌کنند ‎-o‎ و ‎-a‎ گزینه‌های ‎
#       .برای اشاره به این مورد ‎Patrick Callahan‎ با تشکر از‎


if [ "$a" -eq 24 -a "$b" -eq 47 ]
then
  echo "Test #3 succeeds."
else
  echo "Test #3 fails."
fi


if [ "$a" -eq 98 -o "$b" -eq 47 ]
then
  echo "Test #4 succeeds."
else
  echo "Test #4 fails."
fi


a=rhino
b=crocodile
if [ "$a" = rhino ] && [ "$b" = crocodile ]
then
  echo "Test #5 succeeds."
else
  echo "Test #5 fails."
fi

exit 0

عملگرهای && و || در یک مضمون حسابی نیز مورد استفاده واقع می‌شوند.

bash$ echo $(( 1 && 2 )) $((3 && 0)) $((4 || 0)) $((0 || 0))
1 0 1 0

عملگرهای متفرقه

,

عملگر کاما

عملگر کاما دو یا چند عملیات حسابی را بهم زنجیر می‌کند. تمام عملکردها (با آثار جانبی محتمل) ارزیابی می‌شوند. [2]

let "t1 = ((5 + 3, 7 - 1, 15 - 4))"
echo "t1 = $t1"        #  ^^^^^^   t1 = 11
#   معادل نتیجه آخرین عملیات تنظیم می‌شود. چرا؟ ‎t1‎ در اینجا‎

let "t2 = ((a = 9, 15 / 3))"     # ‎"t2"‎ و محاسبه ‎"a"‎ تنظیم‎
echo "t2 = $t2    a = $a"        #  t2 = 5    a = 9

عملگر کاما اساساً در حلقه‌های for مورد استفاده واقع می‌شود. مثال ‎11-13‎ را ببینید.

یادداشت‌ها

[1]

در یک مضمون متفاوت، ‎+=‎ می‌تواند به عنوان یک عملگر الحاق رشته به کار برود. این می‌تواند برای ویرایش متغیرهای محیط سودمند باشد.

[2]

البته آثار جانبی، نتایج ناخواسته -- و معمولاً نامطلوب -- هستند.