آر

آرایه در Bash

{one: "۱ تمرین", other: "%{count} تمرین"}

درباره‌ی آرایه

Bash دو نوع پارامتر فراهم می‌کند: مقادیر «اسکالر» و آرایه‌ها. یک مقدار اسکالر می‌تواند یک رشته یا یک عدد باشد؛ این مقدار نماینده‌ی یک «چیز» منفرد است.

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

آرایه‌ها دو نوع‌اند:

  • آرایه‌های با اندیس عددی، یک کلید عدد صحیح را به یک مقدار رشته‌ای نگاشت می‌کنند. (زبان‌های دیگر ممکن است به آن «لیست» یا «دنباله» بگویند.)
  • آرایه‌های انجمنی، یک کلید رشته‌ای را به یک مقدار رشته‌ای نگاشت می‌کنند. (زبان‌های دیگر ممکن است به آن «مپ» یا «دیکشنری» بگویند.)

بخش‌های اول این سند به آرایه‌های با اندیس عددی می‌پردازد (که از این پس به‌سادگی «آرایه» نامیده می‌شوند). جزئیات مربوط به آرایه‌های انجمنی در پایان می‌آید.

Caution

آرایه‌های Bash فقط می‌توانند مقادیر اسکالر را ذخیره کنند. امکان ساختن یک آرایه‌ی دوبعدی (آرایه‌ی آرایه‌ها) وجود ندارد.

اعلان و مقداردهی اولیه‌ی یک متغیر آرایه

می‌توانید یک آرایه را با انتساب دادن یک لیست عنصر داخل پرانتز (احتمالاً خالی) به یک متغیر مقداردهی اولیه کنید.

myarray=("one" "two" "three")

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

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

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

myarray=(
    "first element"
    "second element"
    "this is the last element"
)

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

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

raindrops=([3]="Pling" [5]="Plang" [7]="Plong")
Note

تکرار می‌کنیم: اندیس‌های آرایه از صفر شروع می‌شوند. این قطعه کد «true» را چاپ می‌کند:

myarray=("one" "two" "three")
[[ "${myarray[0]}" == "one" ]] && echo true || echo false

می‌توانید از دستور declare (یا local درون یک تابع) استفاده کنید تا مشخص کنید که یک متغیر آرایه نگه می‌دارد.

declare -a myarray

روش اصطلاحی‌تر این است که فقط یک لیست داخل پرانتز (احتمالاً خالی) را برای مقداردهی اولیه‌ی متغیر انتساب دهید.

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

همان‌طور که در نکته‌ی بالا دیدید، نحوه‌ی نگارش دسترسی به یک عنصر آرایه ${myarray[$index]} است. اندیس داخل کروشه نوشته می‌شود. آکولادها الزامی‌اند.

Note

برای آرایه‌های با اندیس عددی، اندیس یک عبارت حسابی است. راهنمای Bash می‌گوید:

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

این یعنی برای بسط «ساده‌ی» متغیر، $ لازم نیست. می‌توانید عنصرها را به این شکل به دست آورید، که کمی خواناتر است:

i=5
echo "${myarray[i]}"
# ..............^

اگر اندیس داده‌شده در آرایه وجود نداشته باشد، نتیجه‌ی بسط یک رشته‌ی خالی است.

انتساب به یک آرایه

برای انتساب به یک عنصر خاص از آرایه، از این نحوه‌ی نگارش استفاده کنید:

myarray[10]="hello"

برای افزودن به انتهای یک آرایه، از عملگر انتساب الحاقی += و از پرانتزها استفاده کنید:

myarray+=("new element 1" "new element 2")

پیمایش یک آرایه

معمولاً لازم است روی مقدارهای یک آرایه پیمایش کنید. از یک حلقه‌ی For استفاده کنید (همان که در مفهوم حلقه دیدید):

myarray=("one" "two" "three")
for value in "${myarray[@]}"; do
    echo "$value"
done

به نحوه‌ی نگارش ویژه‌ی بسط آرایه توجه کنید: "${myarray[@]}" این شکل از بسط پارامتر، مقدارهای آرایه را به‌صورت کلمه‌های جداگانه جای‌گذاری می‌کند. تا حدودی معادل این است:

for value in "${myarray[0]}" "${myarray[1]}" ... "${myarray[n]}"

شکل "${myarray[@]}" با آرایه‌های پراکنده هم کار می‌کند و فقط به مقدارهای تعریف‌شده بسط می‌یابد.

این بسط ویژه، که در آن اندیس @ است، تنها درون دابل‌کوتیشن ویژه محسوب می‌شود.

بسط‌های ویژه‌ی دیگر پارامتر

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

برای یافتن طول یک آرایه، از ${#myarray[@]} استفاده کنید، با یک # پیش از اسم. منظور از «طول» یک آرایه، تعداد عنصرهای آن است.

برای استخراج لیست اندیس‌های یک آرایه، از "${!myarray[@]}" استفاده کنید، با یک ! پیش از اسم و با قرار دادن بسط در دابل‌کوتیشن. برای آرایه‌های با اندیس عددی، اندیس‌ها به ترتیب عددی بسط می‌یابند.

پیمایش روی اندیس‌های آرایه

گاهی هم به اندیس نیاز دارید و هم به مقدار. چند راه برای این کار وجود دارد.

  1. وقتی می‌دانید اندیس‌ها یک دنباله‌ی بدون وقفه می‌سازند، می‌توانید از یک حلقه‌ی For حسابی استفاده کنید.

    for ((i = 0; i < ${#myarray[@]}; i++)); do
        echo "$i -> ${myarray[i]}"
    done
    

    به نحوه‌ی نگارش ${#myarray[@]} توجه کنید، با کاراکتر # جلوی اسم آرایه. چون آرایه‌ها اندیس‌گذاری را از صفر شروع می‌کنند، آخرین اندیس آرایه یکی کمتر از طول آرایه است.

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

    for index in "${!raindrops[@]}"; do
        echo "$index -> ${raindrops[index]}"
    done
    

    به نحوه‌ی نگارش ${!myarray[@]} توجه کنید، با کاراکتر ! جلوی اسم آرایه.

بررسی محتوای یک آرایه

اگر می‌خواهید محتوای یک آرایه را ببینید، از دستور declare با گزینه‌ی -p استفاده کنید:

a=("the 'first' element"
   second
   third
   'the "last" element')
declare -p a

این کار محتوا را با نقل‌قول استاندارد شل چاپ می‌کند.

declare -a a=([0]="the 'first' element" [1]="second" [2]="third" [3]="the \"last\" element")

آرایه‌های انجمنی

تکرار می‌کنیم که آرایه‌های انجمنی برای اندیس‌ها از رشته استفاده می‌کنند، نه از عدد. همه‌ی آنچه در بالا نوشته شد برای آرایه‌های انجمنی هم برقرار است، اما با تفاوت‌های کوچک. به‌طور کلی، ما به‌جای «اندیس» از اصطلاح «کلید» استفاده می‌کنیم: آرایه‌های انجمنی کلیدها را به مقدارها نگاشت می‌کنند.

اعلان یک آرایه‌ی انجمنی

برخلاف آرایه‌های معمولی، آرایه‌های انجمنی باید اعلان شوند. از گزینه‌ی -A برای declare (یا local درون یک تابع) استفاده کنید:

declare -A mymap

myfunc() {
    local -A my_local_map
    # ...
}

مقداردهی اولیه‌ی یک آرایه‌ی انجمنی

جفت‌های کلید-مقدار درون لیست داخل پرانتز مشخص می‌شوند:

mymap=([first]=foo [second]=bar [third]=baz)
declare -p mymap

این خروجی را می‌دهد:

declare -A mymap=([second]="bar" [first]="foo" [third]="baz")
Note

توجه داشته باشید که آرایه‌های انجمنی بدون ترتیب هستند.

اعلان و مقداردهی اولیه می‌توانند در یک خط انجام شوند.

declare -A mymap=([first]=foo [second]=bar [third]=baz)

در نسخه‌های اخیر Bash، مقداردهی اولیه می‌تواند از یک لیست (key value key value ...) استفاده کند.

declare -A mymap=(first foo second bar third baz)

دسترسی به مقدارها

برای دسترسی به عنصرها از همان نحوه‌ی نگارشی که پیش‌تر دیدیم استفاده می‌شود: ${mymap[$key]}.

کلیدهای آرایه‌ی انجمنی در بستر حسابی ارزیابی نمی‌شوند. نحوه‌ی نگارش معمول بسط پارامتر لازم است.

انتساب به یک آرایه‌ی انجمنی

انتساب از همان نحوه‌ی نگارشی که پیش‌تر دیدیم استفاده می‌کند:

mymap[$key]="$value"

پیمایش

می‌توانید برای پیمایش از یک حلقه‌ی for value in "${mymap[@]}" استفاده کنید. اما معمولاً می‌خواهید کلید هم همراه مقدار بیاید.

از نحوه‌ی نگارش "${!mymap[@]}" که در بالا دیدیم استفاده کنید.

for key in "${!mymap[@]}"; do
    echo "$key -> ${mymap[$key]}"
done

این خروجی را می‌دهد

second -> bar
first -> foo
third -> baz

باز هم تأکید می‌کنیم که کلیدها هیچ ترتیبی ندارند.

ویرایش از طریق GitHub این پیوند در پنجره یا زبانه‌ی جدیدی باز می‌شود