ما مراجعه به یک متغیر، $var را دیدهایم، مقدار آن را اخذ میکند. اما، در مورد مقدار یک مقدار چطور؟ در مورد $$var چطور؟
نشانهگذاری واقعی به صورت \$$var است که به طور معمول یک eval (و گاهی اوقات یک echo نیز) جلوی آن قرار گرفته است. این یک مراجعه غیرمستقیم نامیده میشود.
مثال 28-1. ارجاعهای غیرمستقیم متغیر
#!/bin/bash #مراجعه غیرمستقیم به متغیر. #دستیابی به محتویات محتویات یک متغیر. #نخست، بیایید کمی ساده نگاه کنیم. var=23 echo "\$var = $var" # #تا اینجا، همه چیز مطابق انتظار. اما... echo "\$\$var = $$var" # #مفید نیست... #$$ به PID اسکریپت بسط یافته است #-- به محتوای متغیر $$ مراجعه کرده -- #+و var به عنوان یک متن ساده منعکس میشود. #(تشکر از Jakob Bohm برای اشاره کردن به این مورد.) echo "\\\$\$var = \$$var" # #همانطور که انتظار میرود. $ اول از تفسیرمعاف میشود #+و به محتوای var (یعنی $var = 23) پیوست میشود. #با معنی است، اما هنوز مفید نیست. #اکنون بیایید دوباره شروع کرده و درست انجام بدهیم. # a=letter_of_alphabet #متغیر «a» نام یک متغیر دیگر را نگهداری میکند. letter_of_alphabet=z echo #مراجعه مستقیم. echo "a = $a" # #مراجعه غیر مستقیم. eval a=\$$a #اجبار به یک ارزیابی «eval(uation)»، و ... #معاف کردن $ اول از تفسیر شدن ... #------------------------------------------------------------------------ #دستور eval به هنگامسازی $a اجبار کرده، آن را به مقدار روزآمد شده \$$a #تنظیم میکند. بنابراین متوجه میشویم که چرا اغلب در نشانهگذاری ارجاع غیر #مستقیم، فرمان eval حضور پیدا میکند. #----------------------------------------------------------------------- echo "Now a = $a" # echo #حال بیایید تغییر مراجعه مرتبه دوم را امتحان کنیم. t=table_cell_3 table_cell_3=24 echo "\"table_cell_3\" = $table_cell_3" # echo -n "dereferenced \"t\" = "; eval echo \$$t # #در این حالت ساده، مورد پایین هم کار میکند (چرا؟). # echo t=table_cell_3 NEW_VAL=387 table_cell_3=$NEW_VAL echo "Changing value of \"table_cell_3\" to $NEW_VAL." echo "\"table_cell_3\" now $table_cell_3" echo -n "dereferenced \"t\" now "; eval echo \$$t #«eval» دو شناسه «echo» و «\$$t» (تنظیم معادل $table_cell_3) را میگیرد #مترجم: در واقع جمله eval echo \$$t به echo $table_cell_3 تبدیل میشود. echo #(تشکر از Stephane Chazelas برای روشن کردن رفتار فوق.) #یک شیوه سر راستتر، نشانهگذاری ${!t} است، که در بخش «Bash، نگارش 2» در #مورد آن بحث گردیده است. همچنین اسکریپت ex78.sh را ببینید. exit 0
فایده عملی مراجعه غیرمستقیم چیست؟ کمی از قابلیت اشارهگرها در C را به Bash میدهد، به طور نمونه، در مراجعه به جدول. و دارای کاربردهای بسیار جالب دیگری نیز هست. . . .
Nils Radtke چگونگی ساختن نام متغیرهای «پویا» و ارزیابی محتویات آنها را نشان میدهد. این کار، هنگام منبع کردن فایلهای پیکربندی میتواند مفید باشد.
#!/bin/bash #------------------------------------------- #این اطلاعات میتواند از یک فایل جداگانه «منبع بشود». isdnMyProviderRemoteNet=172.16.0.100 isdnYourProviderRemoteNet=10.0.0.10 isdnOnlineService="MyProvider" #------------------------------------------- remoteNet=$(eval "echo \$$(echo isdn${isdnOnlineService}RemoteNet)") remoteNet=$(eval "echo \$$(echo isdnMyProviderRemoteNet)") remoteNet=$(eval "echo \$isdnMyProviderRemoteNet") remoteNet=$(eval "echo $isdnMyProviderRemoteNet") echo "$remoteNet" #172.16.0.100 #================================================================ #و حتی بهتر از آن هم میشود. #قطعه کد زیر را که در آن متغیری به نام getSparc معلوم، اما متغیری #+همچون getIa64 در آن نامعلوم است، ملاحظه نمایید: chkMirrorArchs () { arch="$1"; if [ "$(eval "echo \${$(echo get$(echo -ne $arch | sed 's/^\(.\).*/\1/g' | tr 'a-z' 'A-Z'; echo $arch | sed 's/^.\(.*\)/\1/g')):-false}")" = true ] then return 0; else return 1; fi; } getSparc="true" unset getIa64 chkMirrorArchs sparc echo $? #0 #True chkMirrorArchs Ia64 echo $? #1 #False #نکتهها: #----------- #بخش نام متغیر که باید جایگزین بشود، به طور واضح ساخته میشود. #پارامترها برای فراخوانهای chkMirrorArchs با حروف کوچک هستند. #نام متغیر متشکل از دو بخش است: «get» و «Sparc» . . .
مثال 28-2. رد کردن یک مرجع غیرمستقیم به awk
#!/bin/bash #نگارش دیگری از اسکریپت «column totaler» که مجموع یک ستون #+مشخص شده (از اعداد) در فایل مورد نظر را محاسبه می کند. #این یکی از موارد استفاده ارجاعهای غیرمستقیم است. ARGS=2 E_WRONGARGS=85 if [ $# -ne "$ARGS" ] #کنترل صحت تعداد شناسههای خط فرمان. then echo "Usage: `basename $0` filename column-number" exit $E_WRONGARGS fi filename=$1 #نام فایل برای انجام عملیات بر روی آن. column_number=$2 #شماره ستون برای جمع کردن. #========= تا این نقطه، همانند با اسکریپت اولیه ========= #یک اسکریپت چند سطری awk به این صورت احضار میشود # # # # # #شروع اسکریپت awk. #------------------------------------------------- awk " { total += \$${column_number} #مراجعه غیرمستقیم } END { print total } " "$filename" #توجه نمایید که awk به eval جلوی \$$ نیاز ندارد. #------------------------------------------------- #پایان اسکریپت awk. #ارجاع متغیر غیرمستقیم از دردسر مراجعه کردن به یک #+متغیر پوسته در اسکریپت تعبیه شده awk پرهیز میکند. #Stephane Chazelas متشکرم. exit $?
این شیوه مراجعه کردن غیرمستقیم کمی ترفندگونه است. اگر متغیر مرتبه دوم مقدارش تغییر کند، آنوقت متغیر مرتبه اول باید به طور صحیحی (همچون در مثال فوق) دستیابی بشود. خوشبختانه، نشانهگذاری ${!variable} معرفی شده با Bash نگارش 2 (مثال 37-2 و مثال A-22 را ببینید) مراجعه غیرمستقیم را بیشتر قابل فهم مینماید. |