اول، شما باید معین کنید مقصود شما از «عدد» چیست. در اکثر حالتهای رایج که مردم این مورد را سؤال میکنند، به نظر میرسد منظور «یک عدد صحیح غیر منفی، بدون علامت + » است. یا به بیان دیگر رشتهای از تمام ارقام. سایر اوقات، افراد میخواهند یک ورودی ممیز شناورِ با علامت و نقطه اعشار اختیاری را تعیین اعتبار نمایند.
اگر شما در حال اعتبار سنجی ساده «رشتهای از ارقام» میباشید، میتوانید آن را با glob انجام بدهید:
# Bash if [[ $foo != *[!0-9]* ]]; then echo "'$foo' is strictly numeric" else echo "'$foo' has a non-digit somewhere in it" fi
همان کار با کاربرد case میتواند در پوستههای Korn و POSIX به خوبی انجام شود:
# ksh, POSIX case "$foo" in *[!0-9]*) echo "'$foo' has a non-digit somewhere in it" ;; *) echo "'$foo' is strictly numeric" ;; esac
اگر به مجاز نمودن یک علامت منفی مقدم، یا اگر به عدد معتبر با ممیز شناور یا مورد دیگر پیچیدهتری نیاز دارید، آنوقت چند روشِ ممکن موجود است. globهای استاندارد به اندازه کافی برای این کار گویا نیستند، اما میتوانیم از globهای توسعهیافته استفاده کنیم:
# Bash --های توسعه یافته باید فعال شوندglob # .کنترل میکند که آیا متغیر تماماً متشکل از ارقام است shopt -s extglob [[ $var == +([0-9]) ]]
یک حالت پیچیدهتر:
# Bash shopt -s extglob [[ $foo = *[0-9]* && $foo = ?([+-])*([0-9])?(.*([0-9])) ]] && echo "foo is a floating-point number"
تست مقدم بر $foo برای اطمینان از وجود حداقل یک رقم میباشد. glob توسعهیافته، به تنهایی رشته تهی، یا + یا - تنها را میتواند مطابقت کند، که شاید رفتار مطلوب نباشد.
پوسته Korn به طور پیشفرض globهای توسعهیافته فعال دارد، اما فاقد [[ است، بنابراین برای انجام انطباق جانشین باید از case استفاده کنیم:
# Korn case $foo in *[0-9]*) case $foo in ?([+-])*([0-9])?(.*([0-9]))) echo "foo is a number";; esac;; esac
توجه نمایید که این کُد از همان glob توسعهیافته استفاده میکند که Bash در مثال قبل به کار برد، سومین پرانتز بسته، در انتهای آن در حقیقت بخشی از ترکیب دستوری case میباشد.
اگر تعریف شما از «عدد معتبر» حتی پیچیدهتر است، یا اگر نیاز به راه حلی دارید که در پوستههای موروثی Bourne کار کند، شاید ترجیح بدهید از ترکیب دستوری عبارت منظمِ یک ابزار خارجی استفاده کنید. نگارش قابل حمل(که در اینجا به طور تفصیلی تشریح شده)، با استفاده از egrep:
# Bourne if echo "$foo" | egrep '^[-+]?([0-9]+\.?|[0-9]*\.[0-9]+)$' >/dev/null then echo "'$foo' is a number" else echo "'$foo' is not a number" fi
Bash نگارش 3 و بالاتر در فرمان [[ دارای پشتیبانی از عبارت منظم میباشد. به سبب باگها و تغییرات در پیادهسازی ویژگی =~ در bash 3.x، ما استفاده از آن را پیشنهاد نمیکنیم، اما در هر صورت افراد از آن استفاده میکنند، بنابراین ما باید در اینجا این مثال را حفظ کنیم (و این هشدار بازدارنده را نیز نگاه داریم، تا وقتی مردم آن را حذف کنند):
# Bash # عبارت منظم را در متغیر قرارمیدهیم <3.2 برای سازگاری معکوس با نگارشهای regexp='^[-+]?[0-9]*(\.[0-9]*)?$' if [[ $foo = *[0-9]* && $foo =~ $regexp ]]; then echo "'$foo' looks rather like a number" else echo "'$foo' doesn't look particularly numeric to me" fi
# ناموفق است ksh با if [ "$foo" -eq "$foo" ] 2>/dev/null;then echo "$foo is an integer" fi
[ به علت وجود -eq متغیر را تفکیک میکند و آن را به عنوان عدد صحیح تفسیر مینماید. اگر تفکیک موفق باشد به طور بدیهی بررسی صحیح است، اگر ناموفق باشد [ یک پیغام خطا چاپ میکند که 2>/dev/null آنرا پنهان میکند و یک کد وضعیت غیر صفر را تنظیم میکند. به هر حال این شیوه در پوسته ksh ناموفق میشود، زیرا ksh متغیر را به عنوان یک عبارت حسابی ارزیابی میکند.
میتوانید از ترفند مشابهی با printf استفاده کنید:
# POSIX if printf "%f" "$foo" >/dev/null 2>&1; then echo "$foo is a float" fi
میتوانید از %d برای تجزیه یک عدد صحیح استفاده کنید. مراقب باشید که تجزیه میتواند وابسته به منطقه باشد(آیا تصور میرود که باشد؟).
if (("$foo")) >/dev/null 2>&1; then echo "$foo is an integer" fi
دستور (($foo)) سعی میکند foo را به عنوان یک عبارت حسابی صحیح تعیین کند، که اگر foo یک عدد صحیح نباشد یک کد خطای غیر صفر برمیگرداند.
پرسش و پاسخ 54 (آخرین ویرایش 2012-12-02 11:27:59 توسط geirha)