این یک صفحه مختلط میباشد، به علت آنکه موضوع آن پیچیده است. به طور کلی به سه بخش تقسیم شده است: آرایههای انجمنی، ارزیابی متغیرهای غیر مستقیم، و اختصاص متغیرهای غیر مستقیم. در سرتاسر آن مباحث موضوعات برنامهنویسی و مفاهیم پراکنده وجود دارد.
مندرجات
ما اول آرایههای انجمنی را معرفی میکنیم، زیرا در عمده موقعیتهایی که افراد سعی در تخصیص و ارزیابی متغیرهای غیرمستقیم مینمایند، به جای آن باید از آرایههای انجمنی استفاده کنند. برای نمونه، ما بارها کسانی را دیدهایم که میپرسند چطور میتوانند یک گروه متغیرهای وابسته مانند IPaddr_hostname1، IPaddr_hostname2 و به همین ترتیب، داشته باشند. روش مناسبتر برای ذخیره این داده، یک آرایه انجمنی به نام IPaddr است که با hostname(نام میزبان) شاخصگذاری شده باشد.
برای طرحریزی از یک رشته به دیگری، به آرایه شاخصگذاری شده توسط رشته به جای عدد، نیاز دارید. این در AWK به عنوان «آرایههای انجمنی» موجود است، در پرل به عنوان«hashes»، و در Tcl به سادگی به عنوان«arrays». آنها همچنین در ksh93 وجود دارند، که در آنجا شما از آن به این شکل استفاده میکنید:
# ksh93 typeset -A homedir # تعریف میکند ksh93 آرایه انجمنی homedir[jim]=/home/jim homedir[silvia]=/home/silvia homedir[alex]=/home/alex for user in "${!homedir[@]}" # تمام شاخصها(نامهای کاربری) را به شمار میآورد do echo "Home directory of user $user is ${homedir[$user]}" done
BASH از نگارش 4 و بالاتر، از آنها پشتیبانی میکند:
# Bash 4 and up declare -A homedir homedir[jim]=/home/jim # یا homedir=( [jim]=/home/jim [silvia]=/home/silvia [alex]=/home/alex ) ...
در نسخههای Bash قبل از نگارش 4 یا اگر نمیتوانید از ksh93 استفاده کنید، گزینههای شما محدود است. یا به سوی سایر مفسرها(awk، perl، python، ruby، tcl، ...) بروید یا مشکل خود را با ساده سازی آن ارزیابی مجدد نمایید.
وظایف معینی وجود دارند که آرایههای انجمنی برای آنها ابزار کاملاً مناسب و قدرتمندی هستند. وظایف دیگری هستند که برای آنها، زیادهروی، یا حقیقتاً نامناسب میباشند.
فرض کنید چند میزبان خادم با مختصر تفاوتی در پیکربندی آنها داریم، و میخواهیم با ssh در هر یک از آنها فرمانهایی با تفاوت جزئی را اجرا نماییم. یک روشی که میتوانیم به کار ببریم، تنظیم یک گروه فرمانهای ssh، که به آسانی نمیتوانند تغییر کنند(hard-code)، در توابع هر نام میزبان در یک اسکریپت منفرد و فقط اجرای آنها به طور سری یا موازی. (فوراً این را رد نکنید! ساده خوب است.) روش دیگر میتواند ذخیره هر گروه از دستورات به عنوان یک عضو آرایه انجمنی شاخصگذاری شده با نام میزبان باشد:
source "$conf" for host in "${!commands[@]}"; do ssh "$host" "${commands[$host]}" done # :فایلی مشابه این است "$conf" که در آن declare -A commands commands=( [host1]="mvn clean install && cd webapp && mvn jetty:run" [host2]="..." )
این نوعی رویکرد است که از یک زبان سطح بالا انتظار داریم، که در آن میتوانیم اطلاعات سلسله مراتبی را در ساختارهای پیشرفته داده ذخیره نماییم. در اینجا مشکل آنست که، ما میخواهیم واقعاً هر عنصر آرایه انجمنی، یک لیست یا یک آرایه دیگر از رشته فرمانها باشد. اما پوسته به سادگی آن نوع ساختار داده را اجازه نمیدهد.
بنابراین، اغلب سزاوار است یک قدم به عقب برگردیم و به جای سایر زبانهای برنامهنویسی، به ضوابط پوسته ها فکر کنیم . آیا در حال اجرای اسکریپت در یک میزبان راه دور نیستیم؟ پس چرامجموعه پیکربندیها را در اسکریپتها ذخیره نمیکنیم؟ آنوقت ساده است:
#مشخص برای میزبانهایی که دستورات باید در آنها اجرا شوندconfیک سری فایل for conf in /etc/myapp/*; do host=${conf##*/} ssh "$host" bash < "$conf" done # /etc/myapp/hostname is just a script: mvn clean install && cd webapp && mvn jetty:run
اکنون ما نیاز به آرایههای انجمنی ، و همچنین نیاز به حل گروهی از مسائل بسیار ناگوار نقلقولی را برطرف نمودهایم. موازیسازی با Parallel گنو نیز آسان است:
parallel ssh {/} bash "<" {} ::: /etc/myapp/*
قبل از اندیشیدن به استفاده از eval برای تقلید آرایههای انجمنی در یک پوسته قدیمیتر(احتمالاً با ایجاد مجموعهای از نام متغیرها مشابه homedir_alex)، فکر کردن به رویکرد سادهتر یا کاملاً متفاوتی که میتوانید به جای آن به کار ببرید را امتحان کنید. اگر بازهم به نطر میرسد که این دستیابی بهترین کار است،معایب ذیل را ملاحظه نمایید:
نامهای متغیر باید با عبارت منظم ^[a-zA-Z_][a-zA-Z_0-9]* منطبق باشد-- برای مثال، یک نام متغیر نمیتواند شامل کاراکترهای دلخواه باشد بلکه فقط حروف، ارقام و خطزیر مجاز میباشند. نمیتوانیم متغیری شامل نامهای کاربری یونیکس داشته باشیم، برای نمونه، -- نام کاربری hong-hu را ملاحظه کنید. خط تیره '-'نمیتواند بخشی از نام متغیر باشد،بنابراین تمام تلاش برای ایجاد متغیری به نام homedir_hong-hu از ابتدا محکوم به شکست است.
نقلقول برای حصول نتیجه صحیح دشوار است. اگر محتوای رشته(نه نام متغیر) میتواند شامل کاراکترهای فضای سفید و نقلقول باشد،نقلقولی نمودن به طور صحیح برای حفظ آن در هر دو تجزیه پوسته دشوار است. و آن فقط برای ثابتها که در زمان نوشتن برنامه معلوم هستند، شدنی است. (فرمان printf %q پوسته Bash کمک میکند، اما مورد قابل مقایسهای در پوستههای POSIX در دسترس نیست
اگر برنامه گندزدایی، ورودی کاربر را اداره نکند، این میتواند خیلی خطرناک باشد!
بخش آرایهها از راهنما یا پرسش و پاسخ 5 را برای توضیح عمقی و مثالهایی از چگونگی استفاده از آرایهها در Bash، بخوانید.
اگر شما نیاز به یک آرایه انجمنی دارید اما پوسته شما آنها را پشتیبانی نمی کند، لطفاً به جای آن استفاده از AWK را در نظر بگیرید.