المصفوفات في Bash

من موسوعة حسوب

إنشاء المصفوفات

المصفوفة هي متغير يحتوي قيمًا متعددة، وأي متغير قد يُستخدم كمصفوفة، كذلك لا يوجد حد أقصى لحجم المصفوفة ولا يُشترط أن تُفهرس المتغيرات داخل المصفوفة أو تُعيَّن في وقت واحد، وقد تكون المصفوفات صفرية القاعدة أي يُفهرس أول عنصر برقم صفر.

ينفَّذ التصريح غير المباشر عن المتغير (indirect declaration) باستخدام البنية اللغوية التالية:

ARRAY[INDEXNR]=value

يعامَل المفهرِس INDEXER على أنه تعبير حسابي يجب أن يٌقدَّر بعدد موجب، ويتم التصريح الواضح (explicit declaration) للمصفوفة باستخدام أمر declare:

declare -a ARRAYNAME

يُقبَل التصريح مع رقم للفهرسة (index number) لكن سيتم تجاهل رقم الفهرسة، وتُحدد الخواص للمصفوفة باستخدام أمريْ declare و readonly، وتُطبَّق الخواص (attributes) على كل المتغيرات في المصفوفة. كذلك لا يمكن إنشاء مصفوفات مختلطة (mixed arrays)، لكن يمكن إنشاء متغيرات المصفوفة باستخدام التعيينات المجمَّعة بالشكل التالي:

ARRAY=(value1 value2 ... valueN)

تكون القيم عندئذ على الصورة التالية: نص[=رقم الفهرس]، ورقم الفهرس هنا ليس ضروريًا، فإن أُدخِل فيعيَّن الفهرس إليه، وإلا فإن فهرس العنصر يكون (رقم آخر فهرس تم تعيينه + 1)، ويقبل أمر declare هذه الصيغة. أما إن لم تُدخَل أرقام للفهرس فتبدأ الفهرسة من رقم صفر. تضاف العناصر المفقودة أو الإضافية إلى مصفوفة باستخدام البنية اللغوية التالية:

ARRAYNAME[indexnumber]=value

تذكر أن أمر read يسمح بخيار a- الذي يمكنك من تعيين قيم للمتغيرات داخل المصفوفة.

معرفة المتغيرات داخل مصفوفة

استخدم الأقواس المعقوفة {} للحصول على محتوى عنصر في مصفوفة، ذلك ضروري كما ترى من المثال التالي لتجاوز تفسير الصدفة لتوسع المعامِلات، وإن كان رقم الفهرس هو @ أو * فيُشار إلى جميع عناصر المصفوفة.

[hsoub in ~] ARRAY=(one two three)

[hsoub in ~] echo ${ARRAY[*]}
one two three

[hsoub in ~] echo $ARRAY[*]
one[*]

[hsoub in ~] echo ${ARRAY[2]}
three

[hsoub in ~] ARRAY[3]=four

[hsoub in ~] echo ${ARRAY[*]}
one two three four

الإشارة إلى محتوى متغير داخل مصفوفة بدون رقم الفهرس يماثل الإشارة إلى محتوى أول عنصر الذي يشار إليه برقم فهرس 0.

حذف متغيرات المصفوفة

يُستخدم أمر unset لحذف المصفوفات أو المتغيرات التي بداخلها:

[hsoub in ~] unset ARRAY[1]

[hsoub in ~] echo ${ARRAY[*]}
one three four

[hsoub in ~] unset ARRAY

[hsoub in ~] echo ${ARRAY[*]}
<--no output-->

أمثلة للمصفوفات

من الصعب إيجاد أمثلة عملية لاستخدامات المصفوفات، إذ ستجد برامج كثيرة لا تفعل أي شيء تقريبًا في نظامك لكنها تستخدم المصفوفات في حساب سلاسل رياضية مثلًا، وقد يكون ذلك واحد من الأمثلة التي تُحسب أنها "تفعل شيئًا"، فأغلب البرامج تريك فقط ما يمكنك فعله بمصفوفة ما في صورة مبسطة للغاية ونظرية.

والسبب في ذلك هو أن المصفوفات هياكل معقدة، فأغلب الأمثلة العملية التي يمكن استخدام المصفوفات فيها قد نُفِّذت باستخدام مصفوفات أيضًا في المستويات الدنيا في لغة C البرمجية التي كُتبت أغلب أوامر يونكس بها، مثل أمر history الذي يعد مثالًا جيدًا على ذلك. انظر إن شئت ملف fc.def داخل مجلد built-ins في شجرة مصدر Bash، إذ تمت معالجته أثناء تجميع الأوامر المُضمَّنة.

سبب آخر يجعل الأمثلة الجيدة على المصفوفات نادرة هو أن المصفوفات ليست مدعومة من كل الصدفات لذا فإنها تخرق مبدأ التوافقية، والمثال التالي هو أحد الأمثلة النادرة لمصفوفة توزع ملفات الإعدادات لخادم ويب أباتشي على المضيفين (hosts) في مزرعة ويب (web farm):

#!/bin/bash

if [ $(whoami) != 'root' ]; then
        echo "Must be root to run $0"
        exit 1;
fi
if [ -z $1 ]; then
        echo "Usage: $0 </path/to/httpd.conf>"
        exit 1
fi

httpd_conf_new=$1
httpd_conf_path="/usr/local/apache/conf"
login=htuser

farm_hosts=(web03 web04 web05 web06 web07)

for i in ${farm_hosts[@]}; do
        su $login -c "scp $httpd_conf_new ${i}:${httpd_conf_path}"
        su $login -c "ssh $i sudo /usr/local/apache/bin/apachectl graceful"

done
exit 0

ينفَّذ أول اختباريْن للتأكد أن المستخدم الذي ينفذ البرنامج هو المستخدم الصحيح، وينفذه بالوسائط الصحيحة كذلك، وتُسرد أسماء المضيفين الذين يحتاجون للإعداد في مصفوفة farm_hosts، ثم يُزوَّد أولئك المضيفين بملف إعدادات أباتشي، ثم يعاد تشغيل العفريت (daemon) بعدها. لاحظ أن استخدام الأوامر من حزمة Secure Shell التي تشفر الاتصالات إلى المضيفين عن بعد.

ساهم دان ريتشتر (Dan Richter) بالمثال التالي كحل للمشكلة التي واجهته:

" .. لدينا في الشركة عروض على موقعنا، ويجب أن يختبرها أحد العاملين كل أسبوع، لهذا فإن لدينا مهمة cron تملأ مصفوفة بالمرشحين المحتملين لهذه الوظيفة من خلال استخدام date+%W لمعرفة الأسبوع الحالي وتنفّذ عملية نمطية (modulo opertion) لمعرفة الفهرس الصحيح، ويرسل إشعار إلى الشخص المختار في رسالة بريدية."

المثال أدناه لأسلوب حل دان ريتشتر لتلك المشكلة:

#!/bin/bash
# This is get-tester-address.sh 
#
# نختبر أولًا إن كانت الصدفة تدعم المصفوفات.
# (لم يُضف دعم المصفوفات إلا مؤخرًا.)
#
whotest[0]='test' || (echo 'Failure: arrays not supported in this version of
bash.' && exit 2)
                                                                                
#
# قائمة المرشحين، أضف أو أزل المرشحين كما تشاء
#
wholist=(
     'Bob Smith <bob@example.com>'
     'Jane L. Williams <jane@example.com>'
     'Eric S. Raymond <esr@example.com>'
     'Larry Wall <wall@example.com>'
     'Linus Torvalds <linus@example.com>'
   )
#
# احسب عدد المختبِرين المحتملين.
# (كرر العملية حتى نجد نصًا فارغًا.)
#
count=0
while [ "x${wholist[count]}" != "x" ]
do
   count=$(( $count + 1 ))
done
                                                                                
#
# نحسب الآن من عليه الدور.
#
week=`date '+%W'`    	# رقم الأسبوع من السنة.
week=${week#0}       	# احذف أي صفر قد يُبدأ به .
                                                                                
let "index = $week % $count"   # الحساب النمطي للأسبوع = الشخص المختار

email=${wholist[index]}     # اجلب عنوان البريد للشخص المختار.
                                                                                
echo $email     	# اطبع العنوان البريدي للشخص المختار.

يُستخدم هذا البرنامج لاحقًا في برامج أخرى كالبرنامج أدناه الذي يستخدم مستند here:

email=`get-tester-address.sh`   # اعرف من سترسَل إليه الرسالة.
hostname=`hostname`    		# اسم هذا الجهاز.
                                                                                
#
# أرسل رسالة بريدية إلى الشخص المناسب.
#
mail $email -s '[Demo Testing]' <<EOF
The lucky tester this week is: $email
                                                                                
Reminder: the list of demos is here:
    http://web.example.com:8080/DemoSites
                                                                                
(This e-mail was generated by $0 on ${hostname}.)
EOF

انظر أيضًا

مصادر