آرایه‌ها

فصل ‎27‎- آرایه‌ها

نگارش‌های جدیدتر ‎Bash‎ آرایه‌های یک بعدی را پشتیبانی می‌کنند. عناصر آرایه می‌توانند با به کار بردن نماد ‎variable[xx]‎ ارزش‌گذاری بشوند. به طور جایگزین، یک اسکریپت ممکن است تمام آرایه را به وسیله یک دستورالعمل صریح ‎declare -a variable‎ معرفی نماید. برای مراجعه به (بازیابی محتویات)یک عنصر آرایه، نشانه‌گذاری براکت‌های کمانی، ‎${element[xx]}‎ را به کار ببرید.

مثال ‎27-1‎. کاربرد آرایه ساده

#!/bin/bash


area[11]=23
area[13]=37
area[51]=UFOs

#           لازم نیست عناصر آرایه متوالی یا همجوار باشند.

#      برخی عناصر آرایه می‌توانند ارزش گذاری نشده بمانند.
#                          شکاف بین عناصر مورد قبول است.
#در حقیقت، آرایه‌ها با داده‌های پراکنده (آرایه‌های پراکنده)
#+          در نرم‌افزار پردازش صفحه گسترده سودمند هستند.


echo -n "area[11] = "
echo ${area[11]}          #   ‏{‏‎براکت‌های کمانی ‏}‏ لازم است.

echo -n "area[13] = "
echo ${area[13]}

echo "Contents of area[51] are ${area[51]}."

#محتویات متغیر آرایه ارزش‌گذاری نشده خالی چاپ می‌شود (متغیر تهی).
echo -n "area[43] = "
echo ${area[43]}
echo "(area[43] unassigned)"

echo

# حاصل جمع دو عضو آرایه به سومی تخصیص داده شده
area[5]=`expr ${area[11]} + ${area[13]}`
echo "area[5] = area[11] + area[13]"
echo -n "area[5] = "
echo ${area[5]}

area[6]=`expr ${area[11]} + ${area[51]}`
echo "area[6] = area[11] + area[51]"
echo -n "area[6] = "
echo ${area[6]}
#این ناموفق است، زیرا اضافه کردن یک عدد صحیح به یک رشته جایز نیست.

echo; echo; echo

# -----------------------------------------------------------------
#                 یک آرایه دیگر، ‎area2‎
#یک روش دیگر تخصیص متغیرهای آرایه‌ای...
#  ‎array_name=( XXX YYY ZZZ ... )‎

area2=( zero one two three four )

echo -n "area2[0] = "
echo ${area2[0]}
#پس اینطور، شاخص‌گذاری از صفر (عنصر اول آرایه ‎[0]‎ است نه ‎[1]‎).

echo -n "area2[1] = "
echo ${area2[1]}                 #    ‎[1]‎ عنصر دوم آرایه است.
# -----------------------------------------------------------------

echo; echo; echo

# -----------------------------------------------
#                      بازهم یک آرایه دیگر، ‎area3‎
#     بازهم یک روش دیگر تخصیص متغیرهای آرایه‌ای...
#  array_name=([xx]=XXX [yy]=YYY ...)

area3=([17]=seventeen [24]=twenty-four)

echo -n "area3[17] = "
echo ${area3[17]}

echo -n "area3[24] = "
echo ${area3[24]}
# -----------------------------------------------

exit 0

به طوری که دیده‌ایم، یک روش مناسب ارزش‌گذاری یک آرایه کامل، استفاده از نماد ‎array=( element1 element2 ... elementN )‎ است.

base64_charset=( {A..Z} {a..z} {0..9} + / = )
               #با استفاده از بسط ابروی توسعه‌یافته،
               #+ برای مقدار دهی اولیه عناصر آرایه.                
               #استخراج شده از اسکریپت ‎base64.sh‎ در
               #+        پیوست «اسکریپت‌های اهدایی».

مثال ‎27-2‎. قالب‌بندی یک شعر

#!/bin/bash
# چاپ شکیل یکی از اشعار محبوب نگارنده راهنمای ABS.

#   سطرهای شعر (بند منفرد).
Line[1]="I do not know which to prefer,"
Line[2]="The beauty of inflections"
Line[3]="Or the beauty of innuendoes,"
Line[4]="The blackbird whistling"
Line[5]="Or just after."
#توجه نمایید که نقل‌قول، گنجاندن فضاهای سفید را مجاز می‌کند.

#ذکر منبع.
Attrib[1]=" Wallace Stevens"
Attrib[2]="\"Thirteen Ways of Looking at a Blackbird\""
#  این شعر در مالکیت عمومی است (حق تالیف آن منقضی گردیده).

echo

tput bold   # Bold print.

for index in 1 2 3 4 5                  #         پنج سطر.
do
  printf "     %s\n" "${Line[index]}"
done

for index in 1 2                        # دو سطر ذکر منبع.
do
  printf "          %s\n" "${Attrib[index]}"
done

tput sgr0   #تنظیم دوباره ترمینال، مستندات tput را ببینید.

echo

exit 0

#      تمرین:
#   -----------
#اسکریپت را برای چاپ کردن خوش فرم یک شعر از یک فایل داده متنی ویرایش کنید.

متغیرهای آرایه‌ای دارای ترکیب دستوری خوشان هستند، حتی فرمان‌های استاندارد ‎Bash‎ دارای گزینه‌های مخصوصِ وفق داده شده برای به کار بردن با آرایه هستند.

مثال ‎27-3‎. عملیات مختلف آرایه

#!/bin/bash
#  کارهای بیشتری با آرایه‌ها.


 array=( zero one two three four five )
#

echo ${array[0]}       # zero
echo ${array:0}        # zero
#بسط پارامتر اولین عضو، با شروع از محل شماره ‎0‎ (اولین کاراکتر).
echo ${array:1}        # ero
# بسط پارامتر اولین عضو با شروع از محل شماره ‎1‎ (دومین کاراکتر).

#                                                                                                                                                            مترجم:
# echo ${array[3]:2}    # ree
#  بسط پارامتر چهارمین عضو با شروع از محل شماره 2 (کاراکتر سوم)‏

echo "--------------"

echo ${#array[0]}      #                 طول اولین عنصر آرایه.

echo ${#array}         #     طول عضو اول آرایه (نماد جایگزین).

echo ${#array[1]}      # 3
#   طول عضو دوم آرایه. آرایه‌ها در Bash از صفر شاخص‌گذاری می‌شوند.

echo ${#array[*]}      #     تعداد عناصر آرایه.

echo ${#array[@]}      #     تعداد عناصر آرایه.

echo "--------------"

array2=( [0]="first element" [1]="second element" [3]="fourth element" )
#
# نقل‌قول، جای دادن فضای سفید در عضوهای منفرد آرایه را مجاز می‌کند.

echo ${array2[0]}      # 
echo ${array2[1]}      # 
echo ${array2[2]}      #
                       #پرش در مقدار دهی اولیه، بنابراین تهی است.
echo ${array2[3]}      # 
echo ${#array2[0]}     #        (طول اولین عضو)
echo ${#array2[*]}     #  (تعداد عناصر در آرایه)

exit

بسیاری از عملیات رشته‌ای استاندارد، روی آرایه‌ها عمل می‌کنند.

مثال ‎27-4‎. عملیات رشته‌ای روی آرایه‌ها

#!/bin/bash
#  عملیات رشته‌ای روی آرایه‌ها.

#      اسکریپت نوشته ‎Michael Zick‎ است.
#با مجوز در این راهنما استفاده گردیده.
#   بهینه‌سازی‌ها: ‎05 May 08‎‏، ‎04 Aug 08‎.

#به طور کلی، هر عمل رشته‌ای با استفاده از نماد ‎${name ... }‎
#+ می‌تواند با نشانه‌گذاری ‎${name[@] ... }‎ یا ‎${name[*] ...}‎
#+           روی تمام عناصر رشته‌ای در یک آرایه اِعمال گردد.


arrayZ=( one two three four five five )

echo

#             استخراج رشته فرعی 
echo ${arrayZ[@]:0}     # 
#        تمام عناصر.

echo ${arrayZ[@]:1}     # 
#       همه عناصر بعد از عضو ‎[0]‎.

echo ${arrayZ[@]:1:2}   # 
#     فقط دو عضو بعد از عضو ‎[0]‎.

# مترجم:   توجه به دو نمونه‌ زیر در فهم کامل‌تر چگونگی عملکرد موارد فوق موثر است.
#echo ${arrayZ[2]:2}     # ree   استخراج از عنصر شماره 2 با شروع از محل شماره 2
#echo ${arrayZ[2]:2:2}   # re  از عنصر شماره 2، از محل شماره‌ 2، تعداد 2 کاراکتر

echo "---------"


#            پاک کردن رشته فرعی

#حدف کوتاهترین انطباق از ابتدای رشته(ها).

echo ${arrayZ[@]#f*r}   # 
#       #       بر تمام عناصر آرایه اعمال می‌گردد.
                        #با «‎four‎» منطبق می‌شود و آن را حذف می‌کند.

#  حذف بلندترین انطباق از ابتدای رشته(ها)
echo ${arrayZ[@]##t*e}  # 
#      #          بر تمام عناصر آرایه اثر می‌کند.
                        #    با «three» منطبق می‌شود و حذفش می‌کند.

#حذف کوتاهترین انطباق از انتهای رشته(ها)
echo ${arrayZ[@]%h*e}   # 
#       #          بر تمام عناصر آرایه عمل می‌کند.
                        #  با «hree» مطابقت می‌نماید و حذفش می‌کند.

# حذف بلندترین انطباق از انتهای رشته(ها)
echo ${arrayZ[@]%%t*e}  # 
#      #        بر تمام عناصر آرایه اعمال می‌شود.
                        #با«three» تطبیق نموده و آن را حذف می‌کند.

echo "----------------------"


#               تعویض رشته فرعی

#تعویض اولین مورد تطابق رشته فرعی، با جانشین.
echo ${arrayZ[@]/fiv/XYZ}   # 
#           #بر تمام عناصر عمل می‌کند.

# تعویض تمام موارد تطابق رشته فرعی با جانشین.
echo ${arrayZ[@]//iv/YY}    # 
#          # روی تمام عناصر آرایه عمل می‌کند.

#   حذف تمام موارد تطابق رشته فرعی.
#مشخص نکردن رشته جانشین، حذف را پیش‌فرض می‌کند...
echo ${arrayZ[@]//fi/}      # 
                            #بر تمام عناصر آرایه اعمال می‌شود.

#تعویض موارد انطباق جلویی رشته فرعی.
echo ${arrayZ[@]/#fi/XY}    # 
#          #  بر تمام عناصر آرایه عمل می‌کند.

#تعویض موارد انطباق انتهایی رشته فرعی.
echo ${arrayZ[@]/%ve/ZZ}    # 
#          #  بر تمام عناصر آرایه عمل می‌کند.

echo ${arrayZ[@]/%o/XX}     # 
#         # چرا؟

echo "------------------------------"


replacement() {
    echo -n "!!!"
}

echo ${arrayZ[@]/%e/$(replacement)}
#
# 
# ‎stdout‎ تابع ‎replacement()‎ رشته جانشین است.
#   عمل تعویض، در حقیقت یک «تخصیص» است.

echo "-------------------------------------"

#  دستیابی «‎for-each‎» (برای هر یک از عضوها):
echo ${arrayZ[@]//*/$(replacement optional_arguments)}
#
#

#  اکنون، فقط در صورتیکه Bash رشته انطباق را
#+به تابعی که فراخوانی می‌شود عبور بدهد . . .

echo

exit 0

#   قبل از یک تلاش برجسته -- Perl، Python، یا بقیه موارد --
#                                     به خاطر داشته باشید:
#                          ‎$( ... )‎ یک جایگزینی فرمان است.
#              یک تابع به عنوان یک پردازش فرعی اجرا می‌شود.
#   تابع خروجی‌اش را (اگر echo شده باشد) در stdout می‌نویسد.
#      تخصیص، در ترکیب با echo و جایگزینی فرمان می‌تواند از
#+                                     stdout تابع بخواند.
# نماد ‎name[@]‎ مشخص‌کننده (معادل) یک عملیات «‎for-each‎» است.
#              ‎Bash‎ قدرتمندتر از آن است که شما فکر می‌کنید!

جایگزینی فرمان می‌تواند عناصر جداگانه یک آرایه را بسازد.

مثال ‎27-5‎. بار کردن محتویات یک اسکریپت به داخل یک آرایه

#!/bin/bash
#  اسکریپت به یک آرایه بارگذاری می‌کند.
#          بواسطه یک ‎e-mail‎ از ‎Chris Martin‎ (متشکرم!).

script_contents=( $(cat "$0") )    #  محتویات اسکریپت ‎($0)‎ را
                                   #+در یک آرایه ذخیره می‌کند.

for element in $(seq 0 $((${#script_contents[@]} - 1)))
  do                #     ‎${#script_contents[@]}‎ تعداد
                    #+  عناصر در آرایه را ارایه می‌دهد.
                    #
                    #                            پرسش:
                    #               چرا ‎seq 0‎ لازم است؟
                    #تغییر آن به ‎seq 1‎ را امتحان کنید.
  echo -n "${script_contents[$element]}"
                    #    لیست کردن هر فیلد این اسکریپت در یک سطر واحد.
# ‎echo -n "${script_contents[element]}"‎ نیز به سبب ‎${ ... }‎ کار می‌کند.
  echo -n " -- "    #         به کار بردن «--» به عنوان جداکننده فیلد.
done

echo

exit 0

#                        تمرین:
#                       ---------
#اسکریپت را طوری ویرایش نمایید که خودش را در قالب اولیه،
#+به طور کامل با فضای سفید، شکست سطرها، و غیره لیست کند.

در یک مضمون آرایه‌ای، برخی فرمان‌های داخلی Bash دارای مقصود کمی متفاوت هستند. برای مثال،unset عناصر آرایه یا حتی یک آرایه کامل را حذف می‌کند.

مثال ‎27-6‎. برخی خصوصیات ویژه آرایه‌ها

#!/bin/bash

declare -a colors
#تمام فرمان‌های بعدی در این اسکریپت با متغیر colors
#+                 به عنوان یک آرایه رفتار می‌کنند.

echo "Enter your favorite colors (separated from each other by a space)."

read -a colors   #جهت نمایش ویژگی‌های زیر، حداقل ۳ رنگ وارد کنید.
#       گزینه خاص فرمان read برای مجاز نمودن تخصیص عناصر آرایه.

echo

element_count=${#colors[@]}
#       ترکیب دستوری ویژه جهت استخراج تعداد عناصر در آرایه.
#          ترکیب ‎element_count=${#colors[*]}‎ نیز کار می‌کند.
#
#          متغیر «@» تفکیک کلمه داخل نقل‌قول‌ها را میسر می‌کند
#+  (متغیرهای جدا شده به وسیله فضای سفید را استخراج می‌کند).
#
# این با رفتار «‎$@‎» و «‎$*‎» در پارامترهای مکانی مطابقت دارد.

index=0

while [ "$index" -lt "$element_count" ]
do                  #           لیست کردن تمام عناصر آرایه.
  echo ${colors[$index]}
  #   ‎${colors[index]}‎ نیز کار می‌کند، زیرا در درون براکت‌های
  #                                     ‎${ ... }‎ قرار دارد.
  let "index = $index + 1"
  #    یا:
  #
done
# هر عضو آرایه در یک سطر جداگانه لیست می‌گردد. اگر این مطلوب
#        نیست، از ‎echo -n "${colors[$index]} "‎ استفاده کنید
#
# انجام این کار با یک حلقه for به صورت:
# 
# 
#  
# 
# (با تشکر از ‎S.C.‎)

echo

#دوباره، لیست تمام عناصر یک آرایه، اما با کاربرد یک روش برازنده‌تر.
  echo ${colors[@]}         #     ‎echo ${colors[*]}‎ نیز کار می‌کند.

echo

#           فرمان unset عناصر یک آرایه یا تمام آرایه را حذف می‌کند.
unset colors[1]             #                حذف دومین عنصر آرایه.
                            #        دارای همان اثر ‎colors[1]=‎ است
echo  ${colors[@]}          #لیست دوباره آرایه، با غیبت دومین عضو.

unset colors                #    حذف تمام آرایه. ‎unset colors[*]‎ و
                            #+      ‎unset colors[@]‎ نیز کار می‌کند.
echo; echo -n "Colors gone."   
echo ${colors[@]}           #یکبار دیگر لیست آرایه، اکنون تهی است.

exit 0

همچنانکه در مثال قبل دیده‌ایم، هر یک از ترکیب‌های ‎${array_name[@]}‎ یا ‎${array_name[*]}‎ به تمام عناصر آرایه ارجاع می‌دهند. به طور مشابهی، برای بدست آوردن تعداد عناصر در یک آرایه، یکی از نشانه‌گذاری‌های ‎${#array_name[@]}‎ یا ‎${#array_name[*]}‎ را به کار ببرید. ‎${#array_name}‎ طول (تعداد کاراکترهای) ‎${array_name[0]}‎، یعنی اولین عنصر آرایه است.

مثال ‎27-7‎. در باره آرایه‌های تهی و عناصر تهی

#!/bin/bash
#

#  با تشکر از ‎Stephane Chazelas‎ برای مثال اولیه، و تشکر
#+از ‎Michael Zick‎ و ‎Omair Eshkenazi‎ برای گسترش دادن آن.
#        وتشکر از ‎Nathan Coulter‎ برای توضیحات و اصلاحات.


# یک آرایه تهی، با یک آرایه دارای عناصر تهی یکسان نیست.

  array0=( first second third )
  array1=( '' )   # ‎array1‎ شامل یک عضو تهی است.
  array2=( )      # بدون عضو، آرایه ‎array2‎ تهی.
  array3=(   )    #             این آرایه چطور؟


echo
ListArray()
{
echo
echo "Elements in array0:  ${array0[@]}"
echo "Elements in array1:  ${array1[@]}"
echo "Elements in array2:  ${array2[@]}"
echo "Elements in array3:  ${array3[@]}"
echo
echo "Length of first element in array0 = ${#array0}"
echo "Length of first element in array1 = ${#array1}"
echo "Length of first element in array2 = ${#array2}"
echo "Length of first element in array3 = ${#array3}"
echo
echo "Number of elements in array0 = ${#array0[*]}"  #
echo "Number of elements in array1 = ${#array1[*]}"  #
echo "Number of elements in array2 = ${#array2[*]}"  #
echo "Number of elements in array3 = ${#array3[*]}"  #
}

# ===================================================================

ListArray

#آزمون گسترش دادن آن آرایه‌ها.

#  افزودن یک عضو به هر آرایه.
array0=( "${array0[@]}" "new1" )
array1=( "${array1[@]}" "new1" )
array2=( "${array2[@]}" "new1" )
array3=( "${array3[@]}" "new1" )

ListArray

#    یا
array0[${#array0[*]}]="new2"
array1[${#array1[*]}]="new2"
array2[${#array2[*]}]="new2"
array3[${#array3[*]}]="new2"

ListArray

# وقتی به شکل فوق گسترش داده شود، آرایه‌ها پشته هستند ...
#  موارد فوق «push» هستند (آخرین عنصر افزوده به پشته)...
#                               بلندی پشته برابر است با:
height=${#array2[@]}
echo
echo "Stack height for array2 = $height"

#            «pop» (یعنی واکشی بالاترین عنصر پشته) عبارت است از:
unset array2[${#array2[@]}-1]   #آرایه‌ها بر مبنای 0 هستند، یعنی
height=${#array2[@]}            #+    عضو اول دارای شاخص ‎0‎ است.
#.مترجم: بنابراین شاخص آخرین عضو برابر با «تعداد عناصر منهای یک» می‌شود
echo
echo "POP"
echo "New stack height for array2 = $height"

ListArray

#    فقط عنصر دوم و سوم آرایه ‎array0‎ لیست می‌شود.
from=1	          # شاخص‌گذاری از صفر شروع می‌شود.
to=2
array3=( ${array0[@]:$from:$to} )
echo
echo "Elements in array3:  ${array3[@]}"

#مانند یک رشته (آرایه‌ای از کاراکترها) کار می‌کند.
#               امتحان برخی قالب‌های رشته‌ای دیگر.

#  تعویض:
array4=( ${array0[@]/second/2nd} )
echo
echo "Elements in array4:  ${array4[@]}"

#تعویض تمام رشته منطبق شده با الگو.
array5=( ${array0[@]//new?/old} )
echo
echo "Elements in array5:  ${array5[@]}"

#  درست وقتی خیال شما در این مورد آسوده می‌شود . . .
array6=( ${array0[@]#*new} )
echo      #    این یکی ممکن است شما را متعجب نماید.
echo "Elements in array6:  ${array6[@]}"

array7=( ${array0[@]#new1} )
echo     #بعد از ‎array6‎ این نباید یک غافلگیری باشد.
echo "Elements in array7:  ${array7[@]}"

#که بسیار شباهت دارد به . . .
array8=( ${array0[@]/new1/} )
echo
echo "Elements in array8:  ${array8[@]}"

# بنابراین در این مورد چه می‌توان گفت؟

#    عملیات رشته‌ای به طور متوالی روی هر عنصر در ‎var[@]‎ انجام می‌گردد.
#              بنابراین : ‎Bash‎ عملیات برداری رشته را پشتیبانی می‌کند.
#   اگر نتیجه، رشته‌ای به طول صفر باشد، در تخصیص  دادن نتیجه، آن عنصر
#+                                                    ناپدید می‌گردد.
#             اما، اگر بسط در نقل‌قول‌ها باشد، عناصر تهی باقی می‌مانند.

# ‎Michael Zick‎: پرسش، آیا آن رشته‌ها نقل‌قول ضعیف هستند یا نقل‌قول قوی؟
#         ‎Nathan Coulter‎: چیزی به عنوان «نقل‌قول‌های ضعیف» وجود ندارد.
#!   در حقیقت آنچه روی می‌دهد آن است که انطباق الگو در مواردی از قبیل
#!+     ‎${parameter#word}‎ بعد از تمام بسط(کلمه)های دیگر صورت می‌گیرد.


zap='new*'
array9=( ${array0[@]/$zap/} )
echo
echo "Number of elements in array9:  ${#array9[@]}"
array9=( "${array0[@]/$zap/}" )
echo "Elements in array9:  ${array9[@]}"
# این دفعه عناصرِ تهی باقی می‌مانند.
echo "Number of elements in array9:  ${#array9[@]}"


#   درست موقعی که فکر می‌کردید هنوز در کانزاس هستید . . .
#              مترجم: کنایه از «ذهنیت اشتباه داشتن» است.

array10=( ${array0[@]#$zap} )
echo
echo "Elements in array10:  ${array10[@]}"
#اما، اگر zap نقل‌قولی باشد، ستاره در آن تفسیر نخواهد شد.
array10=( ${array0[@]#"$zap"} )
echo
echo "Elements in array10:  ${array10[@]}"
#  بسیار خوب، شاید باز هم ما در کانزاس هستیم . . .
# (بازنگری‌های بلوک کد فوق به وسیله ‎Nathan Coulter‎)


#          آرایه ‎array7‎ را با ‎array10‎ مقایسه کنید.
#           آرایه ‎array8‎ را با ‎array9‎ مقایسه کنید.

#    تاکید دوباره: چیزی به عنوان نقل‌قول ضعیف نیست!
#                        ‎Nathan Coulter‎ شرح می‌دهد:
#  انطباق الگوی «word» در ‎${parameter#word}‎ بعد از
#+  بسط پارامتر و «قبل از» حدف نقل‌قول انجام می‌شود.
#    در حالت عادی، انطباق الگو «بعد از» حذف نقل‌قول
#                                     انجام می‌شود.

exit

نسبت ‎${array_name[@]}‎ و ‎${array_name[*]}‎ قابل مقایسه با نسبت میان ‎$@‎ و ‎$*‎ است. این نشانه‌گذاری قدرتمند آرایه، دارای چند مورد استفاده است.

#رونوشت برداری از یک آرایه.
array2=( "${array1[@]}" )
#   یا
array2="${array1[@]}"
#
#اما این ترکیب به طوری که ‎Jochen DeSmet‎ اشاره می‌کند با آرایه‌های
#+  پراکنده، آرایه‌هایی با حفره(عناصر غایب) در آنها، ناموفق است.
#  ------------------------------------------------------------
  array1[0]=0
                                    # ‎array1[1]‎ تخصیص داده نشده
  array1[2]=2
  array2=( "${array1[@]}" )         #          آن را کپی می‌کند؟

echo ${array2[0]}                   #   0
echo ${array2[2]}                   #  (تهی)، ظاهرا باید ‎2‎ باشد
# -------------------------------------------------------------



#  افزودن یک عنصر به یک آرایه.
array=( "${array[@]}" "new element" )
#   یا
array[${#array[*]}]="new element"

# با تشکر از ‎S.C.‎

tip

عملیات ارزش‌گذاری اولیه ‎array=( element1 element2 ... elementN )‎ به کمک جایگزینی فرمان، بارگیری محتویات یک فایل متن به داخل یک آرایه را امکان‌پذیر می‌سازد.

#!/bin/bash

filename=sample_file

#    cat sample_file‎
#    
#    1 a b c‎
#    2 d e fg‎


declare -a array1

array1=( `cat "$filename"`)     # بارگذاری محتوای ‎$filename‎    
#           #+          
#
# 
# تبدیل کاراکترهای تعویض سطر داخل فایل به کاراکتر فاصله.
#   ضروری نیست، به علت اینکه Bash تفکیک کلمه را با تبدیل
#+                     تعویض سطرها به فاصله‌ انجام می‌دهد.

echo ${array1[@]}                     # لیست کردن آرایه.
                                      # 
#
#   هر کلمه جداشده با فضای سفید در فایل به عضوی از آرایه
#+                                   تخصیص داده شده است.

element_count=${#array1[*]}
echo $element_count                   # 

اسکریپت‌نویسی هوشمندانه، افزایش دادن عملیات آرایه‌ای را امکان‌پذیر می‌نماید.

مثال ‎27-8‎. مقداردهی اولیه آرایه‌ها

#! /bin/bash
# 

#            این عملیات آرایه‌ای مختص Bash است، از اینرو
#+          پسوند ‎.bash‎ در نام اسکریپت به کار رفته است.

#  
#    مجوز: استفاده مجدد نامحدود، به هر طریق، برای هر مقصود.
#   
#
#       شفاف سازی و توضیحات اضافی به وسیله ‎William Park‎

#      بر اساس یک مثال ارایه شده توسط ‎Stephane Chazelas‎
#+       که در یک نگارش‌ قدیمی از این راهنما ظاهر گردید.

#                              قالب خروجی فرمان times :
#                  ‎CPU‎ سیستم  <فاصله> ‎CPU‎ کاربر
# ‎CPU‎ فرزندان مرده سیستم <فاصله> CPU فرزندان مرده کاربر

#     ‎Bash‎ دارای دو نگارش جهت تخصیص تمام عناصر یک آرایه
#+                        به یک متغیر آرایه‌ای جدید است.
#     در Bash نگارش ‎2.04‎ و بعد از آن، هر دوی آنها عناصر
#+                             تهی را از قلم می‌اندازند.
#  شاید یک تخصیص آرایه اضافی که رابطه ‎[subscript]=value‎
#+ برای آرایه‌ها را حفظ کند، در نگارش‌های بعدی اضافه شود.

#    با استفاده از یک فرمان داخلی یک آرایه بزرگ می‌سازد،
#+   اما هر چیز تولید کننده آرایه‌ای با چند هزار عضو نیز
#+                                  مشکلی ایجاد نمی‌کند.

declare -a bigOne=( /dev/* )   # تمام فایل‌های داخل ‎/dev‎
echo
echo 'Conditions: Unquoted, default IFS, All-Elements-Of'
echo "Number of elements in array is ${#bigOne[@]}"

# set -vx



echo
echo '- - testing: =( ${array[@]} ) - -'
times
declare -a bigTwo=( ${bigOne[@]} )
#  به پرانتزها توجه کنید:
times


echo
echo '- - testing: =${array[@]} - -'
times
declare -a bigThree=${bigOne[@]}
# این دفعه بدون پرانتزها.
times

# مقایسه اعداد نشان می‌دهد که شکل دوم ارایه شده
#+      به وسیله ‎Stephane Chazelas‎ سریعتر است.
#
#           به طوری که ‎William Park‎ شرح می‌دهد:
#+  آرایه ‎bigTwo‎ عضو به عضو تخصیص یافته است (به علت وجود پرانتزها)،
#+  در حالیکه آرایه ‎bigThree‎ به صورت یک رشته منفرد تخصیص یافته است.
#                          بنابراین، در اصل، شما به این صورت دارید:
#  
#  
#
#این مطلب را با ‎echo ${bigTwo[0]}‎ و ‎echo ${bigThree[0]}‎ تحقیق کنید.


# من توضیحات مثالم را با استفاده از شکل اول ادامه خواهم داد، به علت
#+   اینکه گمان دارم نمایش تجربی مناسب‌تری است از آنچه اتفاق می‌افتد.

# بخش‌های قابل استفاده مجدد مثال‌های من شامل شکل دوم واقعی خواهند بود
#+                         که این شکل به دلیل سرعت بالا مناسب‌تر است.

#                           ‎MSZ‎: دوستان از اشتباه نظری قبلی متاسفم.


#                             یادداشت:
#                            ---------
# دستورالعمل‌های صریح «‎declare -a‎» در سطرهای ‎31‎ و ‎43‎  ضروری نیستند،
#+       چون به طور ضمنی در ترکیب تخصیص  ‎Array=( ... )‎ قرار دارند.
#    به هرحال، از قلم انداختن این اعلان‌ها اجرای بخش‌های بعدی اسکریپت
#+                                                   را کند می‌کند.
#                                            امتحان کنید و ببینید.

exit 0

اضافه کردن یک ‎declare -a‎ غیر ضروری برای یک اعلان آرایه، ممکن است اجرای عملیات بعدی روی آرایه را تسریع نماید.

مثال ‎27-9‎. رونوشت برداری و الحاق آرایه‌ها

#! /bin/bash
# 
#
# این اسکریپت به وسیله ‎Michael Zick‎ نوشته شده است.
#             با مجوز در اینجا استفاده گردیده است.

#  چگونگی «عبور دادن با نام و برگشت با نام»
#+     یا «ساختن عبارت فرمان تخصیص خودتان».


CpArray_Mac() {

# سازنده عبارت فرمان تخصیص

    echo -n 'eval '
    echo -n "$2"                 #     نام مقصد
    echo -n '=( ${'
    echo -n "$1"                 #     نام منبع
    echo -n '[@]} )'

# تمام آن می‌توانست به صورت یک دستور منفرد باشد.
#                      فقط مسئله سبک نگارش است.
}

declare -f CopyArray             #  نشانگر تابع
CopyArray=CpArray_Mac            # سازنده عبارت

Hype()
{

#                  آرایه‌ای به نام ‎$1‎ را می‌گیرد.
#  (با آرایه‌ای محتوی ‎Really Rocks‎ پیوند می‌زند.)
#             در آرایه‌ای به نام ‎$2‎ برگشت می‌دهد.

    local -a TMP
    local -a hype=( Really Rocks )

    $($CopyArray $1 TMP)
    TMP=( ${TMP[@]} ${hype[@]} )
    $($CopyArray TMP $2)
}

declare -a before=( Advanced Bash Scripting )
declare -a after

echo "Array Before = ${before[@]}"

Hype before after

echo "Array After = ${after[@]}"

#Too much hype?

echo "What ${after[@]:3:2}?"

declare -a modest=( ${after[@]:2:1} ${after[@]:3:2} )
#                    ---- استخراج رشته فرعی ----

echo "Array Modest = ${modest[@]}"

# چه اتفاقی برای before پیش آمده؟

echo "Array Before = ${before[@]}"

exit 0

مثال ‎27-10‎. بیشتر در مورد الحاق آرایه‌ها

#! /bin/bash
# 

# 
#     مجوز:  استفاده مجدد نامحدود در هر شکل، به هر منظور.
#  
#
#       اندکی به وسیله نگارنده ویرایش گردیده است.


#                     عملیات آرایه مختص Bash است.
#      ‎/bin/sh‎ میراث یونیکس فاقد معادل‌های آن است.


# خروجی این اسکریپت را به فرمان more لوله‌کشی کنید
#+ به طوری که بتواند صفحه به صفحه مرور گردد، و یا
#        خروجی آن را به یک فایل تغییر مسیر بدهید.


declare -a array1=( zero1 one1 two1 ) 
#          عناصر مقدار دهی اولیه شده‌اند.
declare -a array2=( [0]=zero2 [2]=two2 [3]=three2 )
# مقدار دهی پراکنده -- ‎[1]‎ مشخص نگردیده.

echo
echo '- Confirm that the array is really subscript sparse. -'
echo "Number of elements: 4"       
# به منظور روشنگری به صورت ثابت وارد گردیده است.
for (( i = 0 ; i < 4 ; i++ ))
do
    echo "Element [$i]: ${array2[$i]}"
done
# همچنین کد عمومی‌تر در مثال A-58 را ببینید.


declare -a dest

#      ترکیب (پیوست) دو آرایه در آرایه سوم.
echo
echo 'Conditions: Unquoted, default IFS, All-Elements-Of operator'
echo '- Undefined elements not present, subscripts not maintained. -'
# #عناصر تعریف نشده، وجود ندارند، آنها از قلم افتاده‌اند.

dest=( ${array1[@]} ${array2[@]} )
#      # نتایج عجیب، یک باگ احتمالی.

# اکنون، لیست کردن نتیجه.
echo
echo '- - Testing Array Append - -'
cnt=${#dest[@]}

echo "Number of elements: $cnt"
for (( i = 0 ; i < cnt ; i++ ))
do
    echo "Element [$i]: ${dest[$i]}"
done

# تخصیص یک آرایه به آرایه تک عضوی (دوبار).
dest[0]=${array1[@]}
dest[1]=${array2[@]}

# لیست کردن نتیجه.
echo
echo '- - Testing modified array - -'
cnt=${#dest[@]}

echo "Number of elements: $cnt"
for (( i = 0 ; i < cnt ; i++ ))
do
    echo "Element [$i]: ${dest[$i]}"
done

# بازرسی عضو دوم ویرایش شده.
echo
echo '- - Reassign and list second element - -'

declare -a subArray=${dest[1]}
cnt=${#subArray[@]}

echo "Number of elements: $cnt"
for (( i = 0 ; i < cnt ; i++ ))
do
    echo "Element [$i]: ${subArray[$i]}"
done

#   تخصیص یک آرایه کامل به یک عضو منفرد از یک آرایه دیگر با استفاده از
#+   تخصیص آرایه ‎=${ ... }‎، آرایه‌ای را که باید تخصیص داده شود تبدیل به
#+ یک رشته متشکل از عناصر جدا شده با فاصله (کاراکتر اول IFS)نموده است.

#              اگر عناصر اولیه شامل فضای سفید نباشند . . .
#      اگر آرایه اولیه دارای ارزش‌گذاری پراکنده نباشد . . .
# آنوقت ما می‌توانیم دوباره ساختار آرایه اصلی را برگردانیم.

# بازیابی عضو دوم ویرایش شده.
echo
echo '- - Listing restored element - -'

declare -a subArray=( ${dest[1]} )
cnt=${#subArray[@]}

echo "Number of elements: $cnt"
for (( i = 0 ; i < cnt ; i++ ))
do
    echo "Element [$i]: ${subArray[$i]}"
done
echo '- - Do not depend on this behavior. - -'
echo '- - This behavior is subject to change - -'
echo '- - in versions of Bash newer than version 2.05b - -'

# ‎MSZ‎: دوستان در باره هر نابسامانی قبلی متاسفم.

exit 0

--

آرایه‌ها گسترش دادن الگوریتم‌های آشنای قدیمی به اسکریپت‌های پوسته را میسر می‌کنند. تصمیم‌گیری در مورد آنکه آیا لزوما این ایده مناسبی است به خواننده واگذار می‌شود.

مثال ‎27-11‎. مرتب‌سازی حبابی

#!/bin/bash
#  مرتب‌سازی حبابی.

# الگوریتم مرتب‌سازی حبابی را به یاد بیاورید. در این نگارش خاص...

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


exchange()
{
  # دو عنصر آرایه را جابجا می‌کند.
  local temp=${Countries[$1]} # ذخیره موقت برای جابجا کردن عنصر.
                              
  Countries[$1]=${Countries[$2]}
  Countries[$2]=$temp
  
  return
}  

declare -a Countries  # تعریف آرایه در اینجا اختیاری است، چون در
                      #+            پایین مقدار دهی اولیه می‌شود.

# دونیم کردن یک متغیر آرایه به چند سطر با به کار بردن یک کاراکتر
#+                                    کاراکتر گریز ‎(\)‎ مجاز است؟
#                                                           بله.

Countries=(Netherlands Ukraine Zaire Turkey Russia Yemen Syria \
Brazil Argentina Nicaragua Japan Mexico Venezuela Greece England \
Israel Peru Canada Oman Denmark Wales France Kenya \
Xanadu Qatar Liechtenstein Hungary)

# 
#+ 


clear                      # پاک کردن صفحه نمایش برای شروع کار. 

echo "0: ${Countries[*]}"  #          لیست آرایه کامل در گذر ‎0‎.

number_of_elements=${#Countries[@]}
let "comparisons = $number_of_elements - 1"

count=1                                    #         شماره گذر.

while [ "$comparisons" -gt 0 ]             # ابتدای حلقه بیرونی
do

  index=0      # بازنشانی شاخص بعد از هر گذر برای ابتدای آرایه.

  while [ "$index" -lt "$comparisons" ]    #  ابتدای حلقه داخلی
  do
    if [ ${Countries[$index]} \> ${Countries[`expr $index + 1`]} ]
    # اگر خارج از ترتیب باشد...
    #یادآوری می‌شود که ‎\>‎ در داخل براکت‌های منفرد عملگر مقایسه اسکی است.

    # 
    #+                                                  نیز کار می‌کند.
    then
      exchange $index `expr $index + 1`                   #   جابجایی.
    fi  
    let "index += 1"        # یا ‎index+=1‎ در ‎Bash‎ نگارش ‎3.1‎ یا جدیدتر.
  done     # انتهای حلقه داخلی

# ------------------------------------------------------------------------
#‎Paulo Marcel Coelho Aragao‎ به عنوان گزینه ساده‌تر حلقه‌ for را توصیه می‌کند.
#
# 
## 
# 
# 
# 
# 
# 
# 
# 
# ----------------------------------------------------------------------
  

let "comparisons -= 1"          #  چون درشت‌ترین عنصر به انتها می‌رود، در 
                                #+  هر گذر به یک مقایسه کمتر نیاز داریم.

echo
echo "$count: ${Countries[@]}"  #  چاپ آرایه حاصل شده، در انتهای هر گذر.
echo
let "count += 1"                #                      افزایش شماره گذر.

done                            #                     انتهای حلقه بیرونی
                                #                             پایان کار.

exit 0

--

آیا جای گرفتن آرایه‌ در داخل آرایه‌ امکان‌پذیر است؟

#!/bin/bash
# آرایه تو در تو.

#   ‎Michael Zick‎ این مثال را فراهم نموده است.
#+ اصلاحات و توضیحات به وسیله‎William Park‎ است.

AnArray=( $(ls --inode --ignore-backups --almost-all \
	--directory --full-time --color=none --time=status \
	--sort=time -l ${PWD} ) )     #فرمان‌ها و گزینه‌ها.

# فاصله‌ها با اهمیت هستند . . . و در بالا چیزی نقل‌قول نشده.

SubArray=( ${AnArray[@]:11:1}  ${AnArray[@]:6:5} )
#                             این آرایه دارای شش عضو است:
#+ 
#  
#
#  آرایه‌ها در ‎Bash‎ لیست‌های پیوندی (دایره‌ای) از نوع رشته ‎(char *)‎ هستند.
# بنابراین، در حقیقت این آرایه تودرتو نیست، اما از نظر وظیفه مشابه است.

echo "Current directory and date of last status change:"
echo "${SubArray[@]}"

exit 0

--

آرایه‌های جاسازی شده در ترکیب با مرجع‌های غیرمستقیم امکانات مجذوب کننده‌ای خلق می‌کنند

مثال ‎27-12‎. آرایه‌های جاسازی شده و مرجع‌های غیر مستقیم

#!/bin/bash
# 
# آرایه‌های جاسازی شده و مرجع‌های غیر مستقیم.

# اسکریپت توسط ‎Dennis Leeuw‎.
#       استفاده شده با مجوز.
#   ویرایش شده توسط نگارنده.


ARRAY1=(
        VAR1_1=value11
        VAR1_2=value12
        VAR1_3=value13
)

ARRAY2=(
        VARIABLE="test"
        STRING="VAR1=value1 VAR2=value2 VAR3=value3"
        ARRAY21=${ARRAY1[*]}
)       #  جاسازی ‎ARRAY1‎ در درون این آرایه دوم.

function print () {
        OLD_IFS="$IFS"
        IFS=$'\n'       #           برای چاپ هر عضو آرایه در یک سطر جداگانه.
        TEST1="ARRAY2[*]"
        local ${!TEST1} # ببینید اگر این سطر را حذف کنید چه اتفاقی رخ می‌دهد.
                        #                                   مرجع غیر مستقیم.
                        #   عناصر ‎$TEST1‎ را برای این تابع قابل دسترس می‌سازد.


        # بیایید ببینیم تا اینجا چه چیزی فراهم کرده‌ایم.
        echo
        echo "\$TEST1 = $TEST1"        # فقط نام متغیر.
        echo; echo
        echo "{\$TEST1} = ${!TEST1}"   # محتویات متغیر.
        #         آنچه که یک مرجع غیرمستقیم انجام می‌دهد

        echo
        echo "-------------------------------------------"; echo
        echo


        #        چاپ متغیر
        echo "Variable VARIABLE: $VARIABLE"
	
        # چاپ یک عنصر رشته
        IFS="$OLD_IFS"
        TEST2="STRING[*]"
        local ${!TEST2}      # مرجع غیرمستقیم (همچون بالا).
        echo "String element VAR2: $VAR2 from STRING"

        # چاپ یک عضو آرایه
        TEST2="ARRAY21[*]"
        local ${!TEST2}      # مرجع غیرمستقیم (همچون بالا).
        echo "Array element VAR1_1: $VAR1_1 from ARRAY21"
}

print
echo

exit 0

#   به طوری که نویسنده اسکریپت یادداشت می‌کند، «می‌توانید به
#+ آسانی آن را برای ایجاد named-hashها در bash بسط بدهید.»
#       تمرین (دشوار) برای خواننده: این کار را انجام دهید.

--

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

مثال ‎27-13‎. غربال اراتوستن

#!/bin/bash
# 

# غربال اراتوستن
# الگوریتم باستانی برای پیدا کردن اعداد اول.

#به نسبت بسیار زیادی، از برنامه معادل آن که در C نوشته شده
#+                              باشد، آهسته‌تر اجرا می‌گردد.

LOWER_LIMIT=1                      #        شروع کردن با ‎1‎
UPPER_LIMIT=1000                   #               تا ‎1000‎
# (اگر وقت اضافی دارید، می‌توانید عدد بزرگتری انتخاب کنید.)

PRIME=1
NON_PRIME=0

let SPLIT=UPPER_LIMIT/2
# بهینه‌سازی:
# فقط نیازمند بررسی اعداد تا نیمه راه حد بالایی است. چرا؟


declare -a Primes
# ‎Primes[]‎ یک آرایه است.


initialize ()
{
# مقدار دهی اولیه آرایه.

i=$LOWER_LIMIT
until [ "$i" -gt "$UPPER_LIMIT" ]
do
  Primes[i]=$PRIME
  let "i += 1"
done
# تا اثبات بی‌گناهی، تمام عناصر آرایه مقصر (عدد اول) فرض می‌شوند.

}

sift ()    #  غیر اول‌ها را غربال می‌کند.
{

let i=$LOWER_LIMIT+1
           # اجازه دهید با ‎2‎ شروع کنیم.

until [ "$i" -gt "$UPPER_LIMIT" ]
# مترجم:  این تابع برای غربال کردن اعدادی که اول نیستند، از طریق یک حلقه while به حذف ضرایب عدد
از میان مجموعه اعداد بین حد پایین و حد بالا اقدام می‌کند. چون هنگامی که از میانه راه حدبالایی عبور کند،   # 
کوچکترین ضریب عدد (ضریب2) بزرگتر از حد بالایی خواهد شد، نیازی به ادامه کار نیست و بنابراین جهت   # 
بهینه‌سازی می‌توانیم در شرط حلقه untile به جای حد بالایی، مقدار نیمه راه یعنی ‎$SPLIT‎ را قرار بدهیم.  # 
do

if [ "${Primes[i]}" -eq "$PRIME" ]
# غربال کردن اعدادی که قبلاً غربال شده‌اند (برچسب غیر اول دارند)، لازم نیست.
then

  t=$i

  while [ "$t" -le "$UPPER_LIMIT" ]
  do
    let "t += $i "
    Primes[t]=$NON_PRIME
    # برچسب زدن تمام مضرب‌ها به عنوان غیر اول.
  done

fi  

  let "i += 1"
done  


}

print_primes ()
{
# اعضای آرایه ‎Primes[]‎ را که برچسب عدد اول دارند، چاپ می‌کند.

i=$LOWER_LIMIT

until [ "$i" -gt "$UPPER_LIMIT" ]
do

  if [ "${Primes[i]}" -eq "$PRIME" ]
  then
    printf "%8d" $i
    #  ‎8‎ فاصله برای هر عدد، ستون‌های تراز مطلوبی ارایه می‌کند.
  fi
  
  let "i += 1"
  
done

}


# ===========================================
# 
# فراخوانی ترتیبی توابع.
initialize
sift
print_primes
# این است آنچه برنامه‌نویسی ساختیافته می‌نامند.
# ===========================================

echo

exit 0



# 
#             کد پایین به علت وجود exit فوق، اجرا نخواهد شد.

#       این نگارش بهبود یافته غربال، نوشته ‎Stephane Chazelas‎
#+                            تا اندازه‌ای سریع‌تر اجرا می‌شود.

#         باید با شناسه خط فرمان (عدد حد بالا) فراخوانی گردد.

UPPER_LIMIT=$1                      #    دریافت از خط فرمان.
let SPLIT=UPPER_LIMIT/2             #    نیمه راه تا حداکثر.

Primes=( '' $(seq $UPPER_LIMIT) )

i=1
until (( ( i += 1 ) > SPLIT ))      # کنترل فقط تا نیمه راه.
do
  if [[ -n ${Primes[i]} ]]
  then
    t=$i
    until (( ( t += i ) > UPPER_LIMIT ))
    do
      Primes[t]=
    done
  fi  
done  
echo ${Primes[*]}

exit $?

مثال ‎27-14‎. غربال اراتوستن، بهینه‌سازی شده

#!/bin/bash
#           غربال اراتوستن بهینه‌سازی شده
#  اسکریپت نوشته ‎Jared Martin‎ با تغییرات بسیار کم به وسیله نگارنده.
#                 در این راهنما با مجوز استفاده گردیده است (تشکر!).

#              بر اساس اسکریپت زیر از راهنمای پیشرفته اسکریپت‌نویسی.
#       

#        مرجع  ‎  http://www.cs.hmc.edu/~oneill/papers/Sieve-JFP.pdf‎
#نتایج را با ‎http://primes.utm.edu/lists/small/1000.txt‎ کنترل کنید.

#                        لازم است اما کافی نخواهد بود، به عنوان مثال
#
#مترجم: برای اجرای دستور فوق، این اسکریپت را در فایلی به نام sieve و جایی از PATH سیستم ذخیره نمایید.

UPPER_LIMIT=${1:?"Need an upper limit of primes to search."}

Primes=( '' $(seq ${UPPER_LIMIT}) )

typeset -i i t
Primes[i=1]=''                                   #          ‎1‎ عدد اول نیست.
until (( ( i += 1 ) > (${UPPER_LIMIT}/i) ))      # فقط تا iمین گذر لازم است.
  do                                             #                     چرا؟
    if ((${Primes[t=i*(i-1), i]}))
               # مبهم، اما آموزنده، استفاده از بسط حسابی در زیرنویس (شاخص).
    then
      until (( ( t += i ) > ${UPPER_LIMIT} ))
        do Primes[t]=; done
    fi
  done

# 
echo           # تعویض با اسکریپت اصلی برای چاپ شکیل (صفحه نمایش ‎80‎ ستونی).
printf "%8d" ${Primes[*]}
echo; echo

exit $?

این تولید کننده‌های عدد اول مبتنی بر آرایه را با نمونه‌های دیگری که از آرایه استفاده نمی‌کنند، مثال A-15، و مثال ‎16-46‎ مقایسه نمایید.

--

آرایه‌ها تا اندازه‌ای برای شبیه‌سازی ساختارهای داده‌ای که ‎Bash‎ دارای پشتبانی ذاتی برای آنها نیست، مناسب هستند.

مثال ‎27-15‎. شبیه‌سازی پشته پایین فشردنی

#!/bin/bash
#  شبیه‌سازی پشته پایین فشردنی

#  مشابه پشته ‎CPU‎، یک پشته پایین فشردنی هم اقلام داده‌ها رابه طور ترتیبی ذخیره
#+ می‌کند، اما آنها را به ترتیب وارونه، آخرین ورودی اولین خروجی، بیرون می‌دهد.


BP=100            #     اشاره‌گر مبنای آرایه پشته. از ‎100‎ شروع می‌شود.

SP=$BP            # اشاره‌گر پشته. مقدار دهی آن با مبنای (پایین)پشته.


Data=             # محتویات جایگاه پشته. به دلیل محدودیت دامنه برگشت 
                  #          تابع، باید از متغیر سراسری استفاده کند.


                  # 
                  # 
                  # 
                  # 
                  # 


declare -a stack


push()                   #                    قرار دادن در پشته.
{
if [ -z "$1" ]           #                  چیزی برای push نیست؟
then
  return
fi

let "SP -= 1"            #              پایین بردن اشاره‌گر پشته.
stack[$SP]=$1

return
}

pop()                    #                  بیرون کشیدن از پشته.
{
Data=                    #                   خالی کردن قلم داده‌.

if [ "$SP" -eq "$BP" ]   #                         پشته تهی است؟
then
  return
fi                       #این همچنین مانع تجاوز ‎SP‎ از ‎100‎ می‌شود،
                         #+ یعنی از یک پشته فراری پیش‌گیری می‌کند.

Data=${stack[$SP]}
let "SP += 1"            #                بالا بردن اشاره‌گر پشته.
return
}

status_report()          #      پی بردن به آنچه در حال وقوع است.
{
echo "-------------------------------------"
echo "REPORT"
echo "Stack Pointer = $SP"
echo "Just popped \""$Data"\" off the stack."
echo "-------------------------------------"
echo
}


# ==================================================
#   اکنون، برای سرگرمی.

echo

#ببینید اگر می‌توانید چیزی از پشته خالی بیرون بکشید.
pop
status_report

echo

push garbage
pop
status_report     #      ورودی آشغال، خروجی آشغال.      

value1=23;        push $value1
value2=skidoo;    push $value2
value3=LAST;      push $value3

pop               # LAST
status_report
pop               # skidoo
status_report
pop               # 23
status_report     #       آخرین ورودی، اولین خروجی!

#  توجه نمایید چگونه با هر push یکی از اشاره‌گر پشته 
#+  کاسته می‌شود و با هر pop یکی به آن افزوده می‌شود.

echo

exit 0

# ===================================================


#                            تمرین‌ها:
#                           ----------

#‎(1‎  تابع ‎"push()"‎ را برای میسر نمودن push کردن چند عنصر بر
#+   روی پشته از طریق یک فراخوانی منفرد تابع، ویرایش کنید.

#  ‎(2‎  تابع ‎"pop()"‎ را برای مجاز نمودن بیرون کشیدن چند عنصر
#+      از پشته با یک فراخوانی منفرد تابع، ویرایش نمایید.

#    ‎(3‎  کنترل خطا برای عملیات حساس اضافه کنید، یعنی، برگشت
#       دادن یک کد خطا بر اساس موفقیت یا عدم موفقیت عملیات،
#+                                و انجام عمل متناسب با آن.

# ‎(4‎  با استفاده از این اسکریپت به عنوان نقطه شروع یک ماشین
#+           حساب چهار عمل اصلی مبتنی بر پشته، بنویسید.

--

دستکاری ماهرانه «زیرنویس‌های» آرایه ممکن است نیازمند متغیرهای واسطه باشد. برای پروژه‌های در برگیرنده این مورد، بار دیگر استفاده از یک زبان برنامه‌نویسی قدرتمند، از قبیل پرل یا C را در نظر بگیرید.

مثال ‎27-16‎. کاربرد آرایه پیچیده: واکاوی یک سری عجیب ریاضی

#!/bin/bash

# ‎Q-series‎ شناخته شده ‎Douglas Hofstadter‎:

# 
# 

#     این یک سری عدد صحیح «درهم و برهم» با رفتار
#+                  عجیب و غیرقابل پیش‌بینی است.
#                بیست جمله نخست سری عبارتند از:
# 

# کتاب ‎_Goedel, Escher, Bach: An Eternal Golden Braid_‎
#+        اثر  ‎Hofstadter‎ صفحه ‎137‎ و بعد آن را ببینید.


LIMIT=100     #        تعداد جمله‌ها برای محاسبه.
LINEWIDTH=20  # تعداد جمله‌های چاپ شده در هر سطر.

Q[1]=1        #         دو جمله اول سری ‎1‎ هستند.
Q[2]=1

echo
echo "Q-series [$LIMIT terms]:"
echo -n "${Q[1]} "             # بیرون دادن دو جمله نخست.
echo -n "${Q[2]} "

for ((n=3; n <= $LIMIT; n++))      # عبارت حلقه به شیوه C
do      #   
# نیاز به شکستن عبارت به جمله‌های میانی است، چون Bash خیلی
#+            خوب آرایه‌های حسابی پیچیده را مدیریت نمی‌کند.

  let "n1 = $n - 1"        # 
  let "n2 = $n - 2"        # 
  
  t0=`expr $n - ${Q[n1]}`  # 
  t1=`expr $n - ${Q[n2]}`  # 
  
  T0=${Q[t0]}              # 
  T1=${Q[t1]}              # 

Q[n]=`expr $T0 + $T1`      # 
echo -n "${Q[n]} "

if [ `expr $n % $LINEWIDTH` -eq 0 ]    # قالب‌بندی خروجی.
then      # 
  echo    #   فاصله دادن بین سطرها برای مرتب شدن قطعه‌ها.
fi

done

echo

exit 0

#    این یک پیاده‌سازی تکرار کننده ‎Q-series‎ است. پیاده‌سازی
#                    بازگشتی به عنوان تمرین واگذار می‌شود.
#  اخطار: محاسبه این سری به طور بازگشتی از طریق یک اسکریپت 
#+  خیلی زیاد طول می‌کشد. ‎C/C++‎ به مراتب سریع‌تر خواهد بود.

--

Bash فقط از آرایه‌های یک بعدی پشتیبانی می‌کند، اگر چه یک ترفند کوچک، شبیه‌سازی آرایه چند بعدی را میسر می‌سازد.

مثال ‎27-17‎. شبیه‌سازی یک آرایه دو بعدی، سپس کج کردن آن

#!/bin/bash

#  شبیه‌سازی یک آرایه دو بعدی.

# یک آرایه یک بعدی از یک سطر واحد تشکیل می‌شود.
#   آرایه دوبعدی سطرهای متوالی را ذخیره می‌کند.

Rows=5
Columns=5
# آرایه ‎5 X 5‎

declare -a alpha     # اعلان ‎char alpha [Rows] [Columns]‎
                     #                   لازم نیست. چرا؟

load_alpha ()
{
local rc=0
local index

for i in A B C D E F G H I J K L M N O P Q R S T U V W X Y
do         # اگر می‌خواهید، از سایر علامت‌ها استفاده کنید.
  local row=`expr $rc / $Columns`
  local column=`expr $rc % $Rows`
  let "index = $row * $Rows + $column"
  alpha[$index]=$i
#  
  let "rc += 1"
done  

#  ترکیب زیر ساده‌تر خواهد بود، اما به نحوی فاقد «طعم» آرایه دو بعدی است.
#+ 
}

print_alpha ()
{
local row=0
local index

echo

while [ "$row" -lt "$Rows" ]   #      چاپ بر حسب شماره سطر: در حالیکه
do                             #+      سطر (حلقه بیرونی) ثابت می‌ماند،
                               #+                   ستون‌ تغییر می‌کند.
  local column=0

  echo -n "       "            #همتراز کردن آرایه مربع با آرایه لوزی.
  
  while [ "$column" -lt "$Columns" ]
  do
    let "index = $row * $Rows + $column"
    echo -n "${alpha[index]} "  # 
    let "column += 1"
  done

  let "row += 1"
  echo

done  

# معادل ساده‌تر آن عبارت است از
# 

echo
}

filter ()     # فیلتر کردن شاخص‌های منفی آرایه.
{

echo -n "  "  #         کج شدن را تامین می‌کند.
              #           چگونگی را شرح بدهید.

if [[ "$1" -ge 0 &&  "$1" -lt "$Rows" && "$2" -ge 0 && "$2" -lt "$Columns" ]]
then
    let "index = $1 * $Rows + $2"
    # اکنون چاپ آن به صورت مایل.
    echo -n " ${alpha[index]}"
    # 
fi    

}
  



rotate ()  #           ‎45‎ درجه دوران آرایه --
{          #+ تراز آن روی گوشه سمت چپ پایینش.
local row
local column

for (( row = Rows; row > -Rows; row-- ))
  do       # پیمایش آرایه به طور وارونه. چرا؟

  for (( column = 0; column < Columns; column++ ))
  do

    if [ "$row" -ge 0 ]
    then
      let "t1 = $column - $row"
      let "t2 = $column"
    else
      let "t1 = $column"
      let "t2 = $column + $row"
    fi  

    filter $t1 $t2     #       فیلتر کردن شاخص‌های منفی آرایه.
                       # اگر این کار را انجام ندهید چه می‌شود؟
  done

  echo; echo

done 

#  چرخش آرایه از مثال (صفحات ‎143-146‎) در «برنامه‌نویسی پیشرفته
#+     ‎C‎ روی ‎IBM PC‎» نوشته ‎Herbert Mayer‎ الهام گرفته شده است.
#+                                 (قسمت کتابنامه را ببینید.)
#   این درست نشان می‌دهد که بیشتر آنچه در C می‌تواند انجام شود، 
#+              در اسکریپت‌نویسی پوسته نیز می‌تواند انجام بشود.

}


#-------------- اکنون، بیاید نمایش را شروع کنیم. -----------
load_alpha     #           بار گرفتن آرایه.
print_alpha    #               چاپ کردن آن.
rotate         # چرخش ‎45‎ درجه‌ای آن در خلاف جهت  عقربه‌های ساعت.
#

exit 0

# این بیشتر یک طرح است، به ظاهر نازیبای آن توجه نکنید.

#                         تمرین‌ها:
#                 -----------------------
# ‎(1‎  توابع بارگیری و جاپ آرایه‌ را با یک شیوه بیشتر قابل درک
#                           و کمتر نامفهوم، بازنویسی نمایید.
#
#     ‎(2‎  معین کنید توابع دوران دادن آرایه چگونه عمل می‌کنند.
#    اشاره: به معنای تلویحی شاخص‌گذاری وارونه آرایه فکر کنید.
#
#  ‎(3‎  این اسکریپت را برای کار کردن با یک آرایه غیر چهار گوش
#                به عنوان مثال یک آرایه ‎6 X 4‎ بازنویسی کنید.
#    موقع چرخاندن آرایه سعی کنید بدریختی آن را کمینه نمایید.

یک آرایه دو بعدی در اصل مانند یک آرایه یک بعدی، اما با شیوه‌های آدرس‌دهی اضافی برای مراجعه و دستکاری عناصر انفرادی به وسیله موقعیت سطر و ستون است.

برای یک مثال با جزییات بیشتر هم، مثال ‎A-10‎ را ببینید.

--

برای اسکریپت‌های جالب‌تر استفاده از آرایه‌ها، مثال‌های زیر را ببینید: