آموزش اسکریپت نویسی

آموزش اسکریپت نویسی پوسته گنو-لینوکس

آموزش اسکریپت نویسی

آموزش اسکریپت نویسی پوسته گنو-لینوکس

پرسش و پاسخ شماره ۵۴

پرسش و پاسخ شماره ۵۴

چگونه می‌توانم بگویم که یک متغیر آیا محتوی یک عدد معتبر هست؟

اول، شما باید معین کنید مقصود شما از «عدد» چیست. در اکثر حالت‌های رایج که مردم این مورد را سؤال می‌کنند، به نظر می‌رسد منظور «یک عدد صحیح غیر منفی، بدون علامت + » است. یا به بیان دیگر رشته‌ای از تمام ارقام. سایر اوقات، افراد می‌خواهند یک ورودی ممیز شناورِ با علامت و نقطه اعشار اختیاری را تعیین اعتبار نمایند.

تفکیک دستی

اگر شما در حال اعتبار سنجی ساده «رشته‌ای از ارقام» می‌باشید، می‌توانید آن را با 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

استفاده از تفکیک انجام شده توسط‎ [‎ و printf(یا استفاده از eq)

# ناموفق است 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)