المسارات
/
Bash
Bash
/
المنهج
/
المزيد عن المصفوفات
ال

المزيد عن المصفوفات في Bash

{zero: "لا توجد تمارين", one: "1 تمرين", two: "تمرينان", few: "%{count} تمارين", many: "%{count} تمرينًا", other: "%{count} تمرين"}

نبذة عن المزيد عن المصفوفات

قدّمنا المصفوفات في فصل المصفوفات. وسيعرض هذا المستند مزيدًا من الأساليب لاستخدام المصفوفات.

ضم عناصر المصفوفة في سلسلة نصية واحدة

في فصل المصفوفات السابق، رأيت "${myarray[@]}"، مع الفهرس @، تُستخدم لتوسيع المصفوفة إلى عناصرها الفردية. لكنك تريد أحيانًا ضمّ كل العناصر في سلسلة نصية واحدة. ولهذا، استخدم الفهرس *:

echo "${myarray[*]}"

يجب أن تُحيط عملية التوسيع بعلامات اقتباس مزدوجة.

يستخدم Bash أول محرف من المتغير المدمج IFS كمحرف فاصل. وبشكل افتراضي، يتكوّن $IFS من مسافة، ومحرف جدولة، ومحرف سطر جديد.

myarray=(one two three four)
mystring="${myarray[*]}"
declare -p mystring
# => declare -- mystring="one two three four"

يمكننا التلاعب بالمتغير IFS لاستخدام محرف فاصل مختلف:

myarray=(one two three four)
IFS=","
mystring="${myarray[*]}"
declare -p mystring
# => declare -- mystring="one,two,three,four"
Advanced
يمكننا تغليف هذا داخل دالة. انقر لعرض التفاصيل.
join() {
    local IFS=$1
    shift
    local elements=("$@")
    echo "${elements[*]}"
}

join ":" "${myarray[@]}"     # note, the "@" index
# => "one:two:three:four"

جعل IFS محليًا داخل الدالة يعني ألا نضطر إلى حفظ القيمة القديمة وإرجاعها إلى قيمتها السابقة في النطاق العام.

وكتحسين إضافي، فإن المعامل الخاص "$*"، عند وضعه بين علامات اقتباس، يؤدي الوظيفة نفسها، فلا نحتاج إلى حفظ نسخة من وسائط الدالة:

join() {
    local IFS=$1
    shift
    echo "$*"
}
من دون استخدام دالة، يُعدّ تعديل `IFS` داخل صدفة فرعية وسيلة جيدة لتجنّب تعديله في الصدفة الحالية. انقر لعرض التفاصيل.
(IFS=","; echo "${myarray[*]}")

تنشئ الأقواس الهلالية صدفة فرعية (نسخة من الصدفة الحالية). وعندما تكتمل الأوامر داخل الأقواس، تخرج الصدفة الفرعية، ويختفي المتغير IFS المُعدّل.

لاحظ أن هذا لن يعمل: IFS="," echo "${myarray[*]}" ؛ إذ يُنفَّذ توسيع المعامل أولًا، قبل أن تطبّق الصدفة المتغير IFS المُعدّل على الأمر echo.

شرائح المصفوفة

ربما رأيت "${variable:offset:length}"، وهو توسيع المعامل الذي يتوسّع إلى سلسلة نصية فرعية من قيمة المتغير. ويمكننا فعل الشيء نفسه مع المصفوفات لتوسيع شريحة من المصفوفة.

myarray=(one two three four)

subarray=("${myarray[@]:0:2}")
declare -p subarray
# => declare -a subarray=([0]="one" [1]="two")

subarray=("${myarray[@]:1:3}")
declare -p subarray
# => declare -a subarray=([0]="two" [1]="three" [2]="four")

حذف جزء الطول يعني «من الإزاحة إلى نهاية المصفوفة»:

subarray=("${myarray[@]:2}")
declare -p subarray
# => declare -a subarray=([0]="three" [1]="four")

تمرير مصفوفة إلى دالة

هذا ليس بهذه البساطة التي قد تعرفها في لغات أخرى. فهناك تقنيتان رئيسيتان لتمرير مصفوفة إلى دالة.

تمرير العناصر

في التقنية الأولى، تمرّر كل قيم المصفوفة وتجمعها في مصفوفة محلية داخل الدالة.

myfunc() {
    local array_copy=("$@")
    # do stuff with array_copy
    declare -p array_copy
}

array_original=(11 22 33 44)
myfunc "${array_original[@]}"

تحتوي مصفوفة الدالة على نسخة من القيم. وأي تغييرات تُجرى على المصفوفة داخل الدالة لا تنعكس على النطاق الخارجي.

تمرير اسم المصفوفة

تشبه هذه التقنية قدرة «التمرير بالمرجع» التي قد تعرفها من لغات أخرى. تمرّر اسم المصفوفة على هيئة سلسلة نصية. وستنشئ الدالة متغيرًا محليًا يحمل السمة nameref. هذه المصفوفة المحلية والمصفوفة العامة (التي مرّرنا اسمها) هما المصفوفة نفسها.

myfunc() {
    # note the `-n` option
    local -n local_array=$1

    # do stuff with local_array
    for i in "${!local_array[@]}"; do
        printf '%d => %s\n' "$i" "${local_array[i]}"
    end

    # we can mutate it
    local_array+=(55 66 77)
}

array_original=(11 22 33 44)
myfunc "array_original"

# show the mutated array
declare -p array_original
# => declare -a array_original=([0]="11" [1]="22" [2]="33" [3]="44" [4]="55" [5]="66" [6]="77")

تعمل سمات nameref أيضًا مع المصفوفات الترابطية، ومع المتغيرات القياسية (التي تحتوي على قيمة من نوع سلسلة نصية).

Note

داخل الدالة، لا يفيد declare -p local_array كثيرًا. إذ سيُخرج فقط declare -n local_array="array_original". ويمكنك الحصول على معلومات مفصّلة عن المصفوفة بفحص اسم المصفوفة الذي مرّرته: declare -p "$1"

Caution

احرص على أن يكون للمصفوفة المحلية اسم مختلف عن اسم المصفوفة الممرّرة. فسيعمل الكود رغم ذلك، لكنه سيُخرج تحذيرات circular name reference مثل هذه:

myfunc() {
    local -n a=$1
    local IFS=,
    echo "${a[*]}"
}

# same name as the function's local variable
a=(one two three)
myfunc a
bash: local: warning: a: circular name reference
bash: warning: a: circular name reference
bash: warning: a: circular name reference
bash: warning: a: circular name reference
one,two,three

المعاملات الموضعية «تشبه المصفوفات»

في الصدفات التي تكتفي بالتوافق مع معيار POSIX (مثل ash وdash)، لا توجد مصفوفات. وأقرب ما يمكنك الوصول إليه هو استخدام المعاملات الموضعية.

  • تُقرأ المعاملات الموضعية بالفهرس: $1 و$2 وهكذا.
  • وتُوسَّع إلى عناصر فردية بواسطة "$@"
  • وتُضمّ في سلسلة نصية واحدة بواسطة "$*"
  • وعدد المعاملات هو $#

استخدم الأمر set لإسناد قيم إليها:

set -- one two three
set -- "$@" four

for item in "$@"; do
    echo "do something with $item"
done

إذا كان هدفك كتابة سكربتات صدفة «محمولة»، فستستخدم المعاملات الموضعية لتخزين «قائمة» من القيم.

تعديل عبر GitHub يفتح الرابط في نافذة أو علامة تبويب جديدة