اگر پرسش واقعی شما «چطور میتوانم بررسی کنم که آیا یکی از پارامترهایم -v است؟» میباشد، پس لطفاً پرسش و پاسخ شماره 35 را ملاحظه کنید.در غیر اینصورت، خواندن را ادامه دهید....
اول از همه، بیایید اصطلاحات را مرتب کنیم. Bash مفهوم لیستها یا مجموعهها یا چیزی از این قبیل ندارد. Bash رشتهها و آرایهها را دارد. رشتهها لیستی از کاراکترها میباشند، آرایهها لیستی از رشتهها هستند.
در یک آرایه سنتی معین، تنها روش صحیحِ انجام این کار، اجرای یک حلقه روی تمام عناصر آرایه و کنترل آنها برای عنصر مورد جستجوی شما میباشد. فرض کنیم آنچه در جستجوی آن هستیم bar است و لیست ما در آرایه foo قرار دارد:
# Bash for element in "${foo[@]}"; do [[ $element = $bar ]] && echo "Found $bar." done
اگر نیاز دارید این کار را چندین مرتبه در اسکریپت خود انجام بدهید، ممکن است بخواهید منطق آنرا در یک تابع به کار ببرید:
# Bash isIn() { local pattern="$1" element shift for element do [[ $element = $pattern ]] && return 0 done return 1 } if isIn "jacob" "${names[@]}" then echo "Jacob is on the list." fi
یا، اگر میخواهید تابع شما شماره شاخص عضوی که عنصر در آن پیدا شده را بازگرداند:
# Bash 3.0 or higher indexOf() { local pattern=$1 local index list shift list=("$@") for index in "${!list[@]}" do [[ ${list[index]} = $pattern ]] && { echo $index return 0 } done echo -1 return 1 } if index=$(indexOf "jacob" "${names[@]}") then echo "Jacob is the ${index}th on the list." else echo "Jacob is not on the list." fi
اگر لیست شما در یک رشته محصور شده، و به دلیل تقریباً نابخردانه، بی پروایی نسبت به هشدارها را انتخاب کردهاید، میتوانید از کُد پایین برای جستجوی کلمات در سرتاسر رشته، استفاده کنید. (تنها عذر موجه برای این مورد میتواند این باشد که شما در پوسته Bourne که آرایه ندارد، گیر افتاده باشید.)
# Bourne set -f for element in $foo; do if test x"$element" = x"$bar"; then echo "Found $bar." fi done set +f
در اینجا کلمه به عنوان هر زیر رشتهای که با فضای سفید(یا به طور دقیقتر کاراکترهای فعلی در متغیر IFS) مرزبندی شده تعریف میشود. دستور set -f از بسط glob در کلمات داخل لیست پیشگیری میکند. فعال کردن مجدد بسط glob با (set +f) اختیاری است.
اگر شما در حال کار با bash نسخه 4 یا ksh93 میباشید، به آرایههای انجمنی دسترسی دارید. اینها به شما اجازه میدهند مشکل را تجدید سازمان بدهید -- به جای ساختن لیستی از کلمات که مجاز هستند، شما میتوانید یک آرایه انجمنی بسازید که در آن کلیدها کلماتی هستند که شما میخواهید در نظر بگیرید. مقادیر آنها -- بسته به طبیعت مشکل --میتوانند با معنی باشند یا نباشند.
# Bash 4 declare -A good for word in "goodword1" "goodword2" ...; do good["$word"]=1 done # مجاز است $foo کنترل اینکه آیا if ((${good[$foo]})); then ...
این هم یک روش دستیابی غیر موجه که شما نباید از آن استفاده کنید، اما به خاطر تکمیل مطلب ارائه میشود:
# Bash if [[ " $foo " = *" $bar "* ]]; then echo "Found $bar." fi
( مشکل در اینجا آنست که فرض میشود space میتواند به عنوان جداکننده بین کلمات استفاده شود. عناصر شما ممکن است شامل فاصله باشند، که این روش را ناموفق میسازد!)
همان روش، برای پوستههای Bourne:
# Bourne case " $foo " in *" $bar "*) echo "Found $bar.";; esac
همچنین میتوانید از glob توسعه یافته با printf برای جستجوی کلمه در یک آرایه استفاده کنید. من این را به اندازه کافی تست نکردهام، بنابراین ممکن است در بعضی موقعیتها ناموفق شود --sn18
# Bash shopt -s extglob # glob تبدیل آرایه به printf -v glob '%q|' "${array[@]}" glob=${glob%|} [[ $word = @($glob) ]] && echo "Found $word"
این کُد موقعی که یک عنصر آرایه شامل کاراکتر
printf %q نیز کاراکتر
grep گنو یک ویژگی \b دارد که که بنا به گفته برخی بر لبههای کلمات مطابقت میکند (مرزهای کلمه). ممکن است شخصی سعی کند با کاربرد آن، رویکرد کوتاهتر استفاده شده فوق را بازآزمایی نماید، اما این کار توأم با خطر است:
# یکی از پارامترهای مکانی است؟ 'foo' آیا egrep '\bfoo\b' <<<"$@" >/dev/null && echo yes # یکی از پارامترهای مکانی است؟ '-v' این جایی است که شکست میخورد: آیا egrep '\b-v\b' <<<"$@" >/dev/null && echo yes # را به صورت یک کلمه جداگانه میبیند "v" , \b متأسفانه # را به چه جهنمی میفرستد "-" کسی نمیداند # هست؟ 'array' در آرایه "someword" آیا کلمه egrep '\bsomeword\b' <<<"${array[@]}" # باشد نمیتوانید از این استفاده کنید '-v' همان someword بدیهی است اگر کلمه
چون این ویژگی grep گنو، هم غیر قابل حمل است و هم به طور ناکافی تعریف شده، پیشنهاد میکنیم از آن استفاده نکنید. این مورد واقعاً در اینجا به خاطر تکمیل کردن مبحث، اشاره میشود.
این شیوه تلاش میکند رشته مورد نظر را با تمام محتویات آرایه مقایسه نماید. به طور بالقوه میتواند بسیار مؤثر باشد، اما بستگی به جداکننده دارد که نباید در کمیت مورد جستجو یا در آرایه موجود باشد. در اینجا ما از
# usage: if has "element" list of words; then ...; fi has() { local IFS=$'\a' t="$1" shift [[ $'\a'"$*"$'\a' == *$'\a'$t$'\a'* ]] }
در ksh93t یا بعد از آن شاید کسی با استفاده از دستور داخلی enum انواع، متغیرها، یا ثابتهای enum ایجاد نماید. اینها به طور مشابه با enumهای C کار میکنند(و خصیصه معادل در سایر زبانها). اینها میتوانند برای محدود نمودن مقادیری که شاید به متغیری اختصاص داده شود، به کار بروند، به طوریکه از لزوم یک بررسی سنگین در هر نوبتی که یک متغیر آرایهای تنظیم یا ارجاع میشود، اجتناب گردد. مانند انواع تولید شده با استفاده از typeset -T، نتیجه یک فرمان enum، فرمان تعریف جدیدی است که میتواند برای معرفی اقلام آن نوع به کار برود.
# ksh93 $ enum colors=(red green blue) $ colors foo=green $ foo=yellow ksh: foo: invalid value yellowمترجم: در کُد فوق، به این دلیل خطا صادر میشود که ما متغیر را چنان تعریف کردهایم که مقادیر قابل تخصیص به آن، به سه رنگ نامبرده محدود گردیده است
typeset -a همچنین میتواند در ترکیب با یک نوع enum برای پذیرفتن ثابتهای enum به عنوان زیرنویس به کار برود.
# ksh93 $ typeset -a [colors] bar $ bar[blue]=test1 $ typeset -p bar typeset -a [colors] bar=([blue]=test) $ bar[orange]=test ksh: colors: invalid value orange
برای مثالهای بیشتر src/cmd/ksh93/tests/enum.sh در منبع AST را ببینید.
پرسش و پاسخ 46 (آخرین ویرایش 2012-07-24 04:36:07 توسط ormaaj)