यदि बैश में एक संख्या एक चर है तो मैं कैसे परीक्षण कर सकता हूं?


597

मैं अभी यह पता नहीं लगा सकता कि मैं कैसे सुनिश्चित करूं कि मेरी स्क्रिप्ट के लिए एक तर्क एक संख्या है या नहीं।

मैं बस यही करना चाहता हूं:

test *isnumber* $1 && VAR=$1 || echo "need a number"

कोई मदद?


17
एक तरफ - test && echo "foo" && exit 0 || echo "bar" && exit 1आपके द्वारा उपयोग किए जा रहे दृष्टिकोण के कुछ अनपेक्षित दुष्प्रभाव हो सकते हैं - यदि प्रतिध्वनि विफल हो जाती है (शायद आउटपुट एक बंद एफडी के लिए है), तो exit 0छोड़ दिया जाएगा, और फिर कोड कोशिश करेगा echo "bar"। यदि यह उस पर भी विफल रहता है, तो &&स्थिति विफल हो जाएगी, और यह भी निष्पादित नहीं करेगा exit 1! / के ifबजाय वास्तविक बयानों का उपयोग करने से अप्रत्याशित दुष्प्रभावों का खतरा कम होता है। &&||
चार्ल्स डफी

@CharlesDuffy उस तरह की चतुर सोच है जो ज्यादातर लोगों को केवल तब मिलती है जब उन्हें बालों के कीड़े को ट्रैक करना पड़ता है ...! मैंने कभी नहीं सोचा था कि प्रतिध्वनि विफलता लौटा सकती है।
कैमिलो मार्टिन

6
पार्टी के लिए थोड़ा देर से, लेकिन मुझे उन खतरों के बारे में पता है, जिनके बारे में चार्ल्स ने लिखा था, क्योंकि मुझे कुछ समय पहले भी उनके माध्यम से जाना था। तो यहां आपके लिए 100% मूर्खतापूर्ण सबूत (और अच्छी तरह से पठनीय) लाइन है: [[ $1 =~ "^[0-9]+$" ]] && { echo "number"; exit 0; } || { echo "not a number"; exit 1; }घुंघराले कोष्ठक इंगित करते हैं कि चीजों को एक उपधारा में निष्पादित नहीं किया जाना चाहिए (जो निश्चित रूप से ()इसके बजाय उपयोग किए गए कोष्ठक के साथ ऐसा होगा )। कैविएट: कभी भी अंतिम अर्धविराम को याद न करें । अन्यथा आप bashबदसूरत (और सबसे व्यर्थ) त्रुटि संदेशों को प्रिंट कर सकते हैं ...
वाक्यविन्यास

5
यह उबंटू में काम नहीं करता है, जब तक आप उद्धरण नहीं हटाते हैं। तो यह बस होना चाहिए[[ 12345 =~ ^[0-9]+$ ]] && echo OKKK || echo NOOO
ट्रेविओनो

4
आपको "संख्या" से जो मतलब है, उसके बारे में अधिक विशिष्ट होना चाहिए । पूर्णांक? एक निश्चित बिंदु संख्या? वैज्ञानिक ("ई") संकेतन? क्या कोई आवश्यक सीमा है (जैसे 64-बिट अहस्ताक्षरित मूल्य), या क्या आप किसी भी संख्या को लिखने की अनुमति देते हैं?
टोबे स्पाइट नाइट

जवाबों:


802

एक दृष्टिकोण एक नियमित अभिव्यक्ति का उपयोग करना है, जैसे:

re='^[0-9]+$'
if ! [[ $yournumber =~ $re ]] ; then
   echo "error: Not a number" >&2; exit 1
fi

यदि मान आवश्यक रूप से पूर्णांक नहीं है, तो उचित रूप से रेगेक्स में संशोधन पर विचार करें; उदाहरण के लिए:

^[0-9]+([.][0-9]+)?$

... या, एक संकेत के साथ संख्याओं को संभालने के लिए:

^[+-]?[0-9]+([.][0-9]+)?$

7
इस दृष्टिकोण के लिए +1, लेकिन दशमलव के साथ ध्यान रखें, इस परीक्षण को उदाहरण के साथ, "1.0" या "1,0" प्रिंट "त्रुटि: नहीं एक संख्या"।
sourcerebels

15
मुझे '' निष्पादन> & 2; गूंज ... '' बल्कि मूर्खतापूर्ण। बस '' प्रतिध्वनि ...> और 2 ''
लूनाथ

5
@ क्या आप वास्तव में एक से अधिक माइनस साइन को संभालना चाहते हैं? जब तक आप वास्तव में कई आक्रमणों को सही ढंग से संभालने के लिए काम नहीं कर रहे हैं ^-?, ^-*तब तक मैं इसे बनाऊंगा।
चार्ल्स डफी

4
@SandraSchlichting भविष्य के सभी आउटपुट को stderr पर ले जाती है। यह वास्तव में यहां एक बिंदु नहीं है, जहां केवल एक ही प्रतिध्वनि है, लेकिन यह एक आदत है जो मुझे उन मामलों के लिए मिलता है जहां त्रुटि संदेश कई पंक्तियों को फैलाते हैं।
चार्ल्स डफी

29
मुझे यकीन नहीं है कि नियमित अभिव्यक्ति को एक चर में क्यों बचाया जाना है, लेकिन अगर यह अनुकूलता के लिए है तो मुझे नहीं लगता कि यह आवश्यक है। आप सीधे अभिव्यक्ति लागू कर सकते हैं [[ $yournumber =~ ^[0-9]+$ ]]:।
konsolebox

282

बशाई के बिना (सिस्टम V श में भी काम करता है),

case $string in
    ''|*[!0-9]*) echo bad ;;
    *) echo good ;;
esac

यह खाली स्ट्रिंग और गैर-अंकों वाले तार को अस्वीकार करता है, बाकी सब को स्वीकार करता है।

नकारात्मक या फ्लोटिंग-पॉइंट नंबरों को कुछ अतिरिक्त काम की आवश्यकता होती है। एक विचार पहले "खराब" पैटर्न को छोड़कर -/ .उनमें "अनुचित" उपयोग करने वाले अधिक "खराब" पैटर्न जोड़ना है ( ?*-*/ *.*.*)


20
+1 - यह मूल बॉर्न शेल के लिए मुहावरेदार, पोर्टेबल तरीका है, और इसमें ग्लोब-शैली वाइल्डगार्ड के लिए अंतर्निहित समर्थन है। यदि आप किसी अन्य प्रोग्रामिंग भाषा से आते हैं, तो यह भयानक लग रहा है, लेकिन यह विभिन्न उद्धरण मुद्दों की भंगुरता और अंतहीन पीछे की ओर मुकाबला करने की तुलना में बहुत अधिक सुरुचिपूर्ण है / अनुकूलता समस्याओं के साथif test ...
ट्रिपल

6
आप पहली पंक्ति को बदल सकते हैं ${string#-}(जो एंटीक बॉर्न शेल में काम नहीं करता है, लेकिन किसी भी POSIX शेल में काम करता है) पूर्णांक को स्वीकार करने के लिए।
गिल्स एसओ- बुराई को रोकना '

4
इसके अलावा, फ़्लोट्स का विस्तार करना आसान है - बस '.' | *.*.*अस्वीकृत पैटर्न में जोड़ें, और अनुमत वर्णों में डॉट जोड़ें। इसी तरह, आप पहले एक वैकल्पिक संकेत की अनुमति दे सकते हैं, हालांकि तब मैं case ${string#[-+]}केवल संकेत को अनदेखा करना पसंद करूंगा ।
ट्रिपल जू

हस्ताक्षरित पूर्णांक को संभालने के लिए इसे देखें: stackoverflow.com/a/18620446/2013911
निकल्स पीटर

2
@ डोर को कोट करने की जरूरत नहीं है, क्योंकि केस कमांड वैसे भी उस शब्द पर शब्द विभाजन और पथनाम पीढ़ी नहीं करता है। (हालाँकि, यदि पैटर्न से मेल खाने वाले अक्षर शाब्दिक या विशेष हैं, तो यह निर्धारित करने की आवश्यकता है कि मामले के पैटर्न में विस्तार हो सकता है।)
जिल्स

193

निम्नलिखित समाधानों को नियमित गोले की आवश्यकता के बिना बोर्न जैसे बुनियादी गोले में भी इस्तेमाल किया जा सकता है। मूल रूप से गैर-संख्याओं का उपयोग करने वाले किसी भी संख्यात्मक मूल्य मूल्यांकन के संचालन में त्रुटि होगी, जिसे अंतर्निहित रूप से शेल में गलत माना जाएगा:

"$var" -eq "$var"

जैसे की:

#!/bin/bash

var=a

if [ -n "$var" ] && [ "$var" -eq "$var" ] 2>/dev/null; then
  echo number
else
  echo not a number
fi

आप $ के लिए परीक्षण भी कर सकते हैं? ऑपरेशन का रिटर्न कोड जो अधिक स्पष्ट है:

[ -n "$var" ] && [ "$var" -eq "$var" ] 2>/dev/null
if [ $? -ne 0 ]; then
   echo $var is not number
fi

मानक त्रुटि का पुनर्निर्देशन "पूर्णांक अभिव्यक्ति अपेक्षित" संदेश को छिपाने के लिए होता है जो हमारे पास संख्या नहीं होने की स्थिति में प्रिंट आउट करता है।

गुफाएं (नीचे टिप्पणी के लिए धन्यवाद):

  • दशमलव बिंदुओं वाली संख्याओं को मान्य "संख्याओं" के रूप में नहीं पहचाना जाता है
  • के [[ ]]बजाय का उपयोग [ ]हमेशा का मूल्यांकन करेंगेtrue
  • अधिकांश गैर-बैश शैल हमेशा इस अभिव्यक्ति का मूल्यांकन करेंगे true
  • बैश में व्यवहार अनैच्छिक है और इसलिए चेतावनी के बिना बदल सकता है
  • यदि मान में संख्या के बाद रिक्त स्थान शामिल है (जैसे "1" a) त्रुटि पैदा करता है, जैसे bash: [[: 1 a: syntax error in expression (error token is "a")
  • यदि मान var-name (जैसे i = "i") के समान है, तो त्रुटि पैदा करता है, जैसे bash: [[: i: expression recursion level exceeded (error token is "i")

8
मैं अब भी इसकी सिफारिश करूंगा (लेकिन खाली तारों के लिए अनुमति देने के लिए उद्धृत चर के साथ), क्योंकि परिणाम को बैश में एक संख्या के रूप में प्रयोग करने योग्य होने की गारंटी है , चाहे कोई भी हो।
l0b0

21
एकल ब्रैकेट का उपयोग करने के लिए ध्यान रखें; [[ a -eq a ]]सत्य का मूल्यांकन (दोनों तर्क शून्य में परिवर्तित हो जाते हैं)
Tgr

3
बहुत अच्छा! ध्यान दें कि यह केवल पूर्णांक के लिए काम करता है, किसी संख्या के लिए नहीं। मुझे एक एकल तर्क की जांच करने की आवश्यकता है जो पूर्णांक होना चाहिए, इसलिए यह अच्छी तरह से काम करता है:if ! [ $# -eq 1 -o "$1" -eq "$1" ] 2>/dev/null; then
haridsv

6
मैं इस पद्धति के खिलाफ दृढ़ता से सलाह [दूंगा क्योंकि गोले की नगण्य संख्या नहीं है, जिसके बिलियन अंकगणित के रूप में तर्कों का मूल्यांकन करेंगे। यह ksh93 और mksh दोनों में सच है। इसके अलावा, उन दोनों समर्थन सरणियों के बाद से, कोड इंजेक्शन के लिए आसान अवसर है। इसके बजाय एक पैटर्न मैच का उपयोग करें।
ओरमज

3
@AlbertoZaccagni, बैश की वर्तमान रिलीज़ में, इन मानों की व्याख्या केवल संख्यात्मक संदर्भ नियमों के साथ की जाती है, [[ ]]लेकिन इसके लिए की जाती है [ ]। उस ने कहा, यह व्यवहार पोसिक्स मानक द्वारा testऔर बैश के स्वयं के प्रलेखन में अनिर्दिष्ट है ; बैश के भविष्य के संस्करणों को किसी भी दस्तावेज व्यवहार वादों को तोड़ने के बिना ksh से मिलान करने के लिए व्यवहार को संशोधित कर सकता है, इसलिए अपने वर्तमान व्यवहार को बनाए रखने पर भरोसा करना सुरक्षित होने की गारंटी नहीं है।
चार्ल्स डफी

43

यह जांचता है कि कोई संख्या एक गैर-नकारात्मक पूर्णांक है और दोनों शेल स्वतंत्र है (अर्थात बिना बशीश) और केवल शेल-इन-इन्स का उपयोग करता है:

गलत।

जब तक यह पहला उत्तर (नीचे) उन वर्णों के साथ पूर्णांक के लिए अनुमति देता है, जब तक कि पहले चर में पहले नहीं होते हैं।

[ -z "${num##[0-9]*}" ] && echo "is a number" || echo "is not a number";

सही

जैसा कि जाइल्स ने अपने जवाब में टिप्पणी की और सुझाव दिया कि यह शेल-पैटर्न का उपयोग करने का सही तरीका है।

[ ! -z "${num##*[!0-9]*}" ] && echo "is a number" || echo "is not a number";

5
यह ठीक से काम नहीं करता है, यह एक अंक के साथ शुरू होने वाले किसी भी स्ट्रिंग को स्वीकार करता है। ध्यान दें कि WORD $ {VAR ## WORD} में है और इसी तरह एक शेल पैटर्न है, न कि एक नियमित अभिव्यक्ति।
जिल्स

2
क्या आप उस अभिव्यक्ति का अंग्रेजी में अनुवाद कर सकते हैं, कृपया मैं वास्तव में इसका उपयोग करना चाहता हूं, लेकिन मैं इस पर विश्वास करने के लिए पर्याप्त नहीं समझता, भले ही बैश मैन पेज पर जाने के बाद।
CivFan

2
*[!0-9]*एक ऐसा पैटर्न है जो कम से कम 1 गैर-अंकीय वर्ण के साथ सभी तार से मेल खाता है। ${num##*[!0-9]*}एक "पैरामीटर विस्तार" है जहां हम numचर की सामग्री लेते हैं और पैटर्न से मेल खाने वाली सबसे लंबी स्ट्रिंग को हटाते हैं। यदि पैरामीटर विस्तार का परिणाम खाली नहीं है ( ! [ -z ${...} ]) तो यह एक संख्या है क्योंकि इसमें कोई गैर-अंक वर्ण नहीं है।
mrucci

दुर्भाग्यवश यह विफल हो जाता है यदि तर्क में कोई अंक हो, भले ही वह वैध संख्या न हो। उदाहरण के लिए "exam1ple" या "a2b"।
स्टूजेक

दोनों के साथ असफल122s :-(
14

40

बश के विस्तारित पैटर्न मिलान का सुझाव किसी ने नहीं दिया :

[[ $1 == ?(-)+([0-9]) ]] && echo "$1 is an integer"

5
ग्लेन, मैं shopt -s extglobआपके पोस्ट से हटाता हूं (जो मैंने ऊपर उठाया है, यह मेरे पसंदीदा उत्तरों में से एक है), चूंकि कंडिशनल कंस्ट्रक्शंस में आप पढ़ सकते हैं: जब ऑपरेटरों ==और !=ऑपरेटरों का उपयोग किया जाता है, तो ऑपरेटर के दाईं ओर स्ट्रिंग को एक पैटर्न और मिलान माना जाता है पैटर्न मिलान में नीचे वर्णित नियमों के अनुसार , जैसे कि extglobशेल विकल्प सक्षम किया गया था। मुझे आशा है कि आप बुरा नहीं मानेंगे!
गनीउर्फ_निगौर्फ

इस तरह के संदर्भों में, आपको यह जानने की आवश्यकता नहीं है shopt extglob... यह अच्छी बात है!
गनीउर्फ_निगौर्फ

सरल पूर्णांक के लिए अच्छी तरह से काम करता है।

2
@ जैमेडियन: आप सही कह रहे हैं, यह बैश 4.1 में जोड़ा गया था (जो 2009 के अंत में जारी किया गया था ... 2006 में बैश 3.2 जारी किया गया था ... यह अब एक एंटीक सॉफ्टवेयर है, जो अतीत में फंस गए हैं उनके लिए खेद है)। इसके अलावा, आप तर्क दे सकते हैं कि एक्सग्लोब जहां संस्करण 2.02 (1998 में जारी) में पेश किए गए, और <2.02 संस्करणों में काम नहीं करते ... अब यहां आपकी टिप्पणी पुराने संस्करणों के बारे में एक चेतावनी के रूप में काम करेगी।
गनीउर_ग्निउरफ सिप ni

1
[[...]]शब्द चर बंटवारे या ग्लोब विस्तार के अधीन नहीं हैं।
ग्लेन जैकमैन

26

मैं सीधे शेल में संख्या स्वरूपों को पार्स करने वाले समाधानों पर हैरान हूं। शेल इस के लिए अच्छी तरह से अनुकूल नहीं है, फाइलों और प्रक्रियाओं को नियंत्रित करने के लिए एक डीएसएल होने के नाते। उदाहरण के लिए पर्याप्त संख्या में पार्सर्स थोड़े नीचे हैं:

isdecimal() {
  # filter octal/hex/ord()
  num=$(printf '%s' "$1" | sed "s/^0*\([1-9]\)/\1/; s/'/^/")

  test "$num" && printf '%f' "$num" >/dev/null 2>&1
}

जो भी विशेष प्रारूप की आवश्यकता हो, उसे '% f' बदलें।


4
isnumber(){ printf '%f' "$1" &>/dev/null && echo "this is a number" || echo "not a number"; }
गाइल्स क्वेनोट

4
@sputnick आपका संस्करण मूल फ़ंक्शन के अंतर्निहित (और उपयोगी) रिटर्न मान शब्दार्थ को तोड़ता है। इसलिए, इसके बजाय, फ़ंक्शन को केवल-छोड़ दें, और इसका उपयोग करें:isnumber 23 && echo "this is a number" || echo "not a number"
माइकल

4
यह भी नहीं होना चाहिए 2>/dev/null, ताकि isnumber "foo"stderr प्रदूषित न हो?
जियोले

4
आधुनिक गोले को कॉल करने के लिए जैसे "फ़ाइलों और प्रक्रियाओं को नियंत्रित करने के लिए एक डीएसएल" इस बात की अनदेखी कर रहा है कि उनका उपयोग इससे कहीं अधिक के लिए किया जाता है - कुछ डिस्ट्रो ने पूरे पैकेज मैनेजर और उस पर वेब इंटरफेस बनाए हैं (जैसा कि बदसूरत हो सकता है)। बैच फाइलें आपके विवरण को फिट करती हैं, हालांकि एक चर सेट करना भी मुश्किल है।
कैमिलो मार्टिन

7
यह मजेदार है कि आप अन्य भाषाओं के कुछ मुहावरों को कॉपी करके स्मार्ट बनने की कोशिश कर रहे हैं। दुर्भाग्य से यह गोले में काम नहीं करता है। गोले बहुत विशेष हैं, और उनके बारे में ठोस ज्ञान के बिना, आपको टूटे हुए कोड लिखने की संभावना है। आपका कोड टूट गया है: isnumber "'a"सही लौटेगा। यह उस POSIX कल्पना में प्रलेखित है जहां आप पढ़ेंगे: यदि अग्रणी वर्ण एकल-उद्धरण या डबल-उद्धरण है, तो मूल्य एकल-उद्धरण या डबल-उद्धरण के बाद वर्ण के अंतर्निहित कोडसेट में संख्यात्मक मान होगा ।
गनीउर्फ़_ग्निऑरफ़

16

मैं जवाब देख रहा था और ... महसूस किया कि किसी ने फ़्लोट संख्या (डॉट के साथ) के बारे में नहीं सोचा था!

Grep का उपयोग करना बहुत अच्छा है।
-ई का अर्थ है विस्तारित रेगेक्स -क्यू का
अर्थ है शांत (गूंज नहीं)
-qE दोनों का संयोजन है।

कमांड लाइन में सीधे परीक्षण करने के लिए:

$ echo "32" | grep -E ^\-?[0-9]?\.?[0-9]+$  
# answer is: 32

$ echo "3a2" | grep -E ^\-?[0-9]?\.?[0-9]+$  
# answer is empty (false)

$ echo ".5" | grep -E ^\-?[0-9]?\.?[0-9]+$  
# answer .5

$ echo "3.2" | grep -E ^\-?[0-9]?\.?[0-9]+$  
# answer is 3.2

बैश स्क्रिप्ट में उपयोग करना:

check=`echo "$1" | grep -E ^\-?[0-9]*\.?[0-9]+$`

if [ "$check" != '' ]; then    
  # it IS numeric
  echo "Yeap!"
else
  # it is NOT numeric.
  echo "nooop"
fi

JUST पूर्णांक से मिलान करने के लिए, इसका उपयोग करें:

# change check line to:
check=`echo "$1" | grep -E ^\-?[0-9]+$`

Triple_r और tripleee द्वारा awk का उपयोग करने वाले समाधान फ्लोट्स के साथ काम करते हैं।
केन जैक्सन

इसके लिए धन्यवाद और बहुत अच्छी बात! कारण सवाल वास्तव में यह जांचना है कि कैसे यह एक संख्या है और न केवल एक पूर्णांक है।
तानियास

मैं भी तानियास धन्यवाद! आइए एक-दूसरे की हमेशा मदद करें।
सर्जियो अब्रू

12

सिर्फ @ मीरी तक एक अनुवर्ती। लेकिन क्योंकि मेरे पास पर्याप्त प्रतिनिधि नहीं हैं, इसलिए मैं उस पोस्ट पर टिप्पणी के रूप में पोस्ट नहीं कर सका। वैसे भी, यहाँ मैं क्या इस्तेमाल किया है:

isnum() { awk -v a="$1" 'BEGIN {print (a == a + 0)}'; }

फ़ंक्शन "1" लौटाएगा यदि तर्क एक संख्या है, अन्यथा "0" वापस आ जाएगा। यह पूर्णांकों के साथ-साथ फ़्लोट के लिए भी काम करता है। उपयोग कुछ इस प्रकार है:

n=-2.05e+07
res=`isnum "$n"`
if [ "$res" == "1" ]; then
     echo "$n is a number"
else
     echo "$n is not a number"
fi

4
एग्जिट कोड सेट करने की तुलना में किसी संख्या को प्रिंट करना कम उपयोगी है। 'BEGIN { exit(1-(a==a+0)) }'थोड़ा मुश्किल है, लेकिन एक फंक्शन में इस्तेमाल किया जा सकता है, जो सही है या गलत है [, जैसे कि grep -q, आदि
tripleee

9
test -z "${i//[0-9]}" && echo digits || echo no no no

${i//[0-9]}किसी भी अंक $iको एक रिक्त स्ट्रिंग के मान से प्रतिस्थापित करता है, देखें man -P 'less +/parameter\/' bash-zजाँच करता है कि परिणामी स्ट्रिंग की लंबाई शून्य है।

यदि आप $iखाली होने पर मामले को बाहर करना चाहते हैं , तो आप इनमें से किसी एक निर्माण का उपयोग कर सकते हैं:

test -n "$i" && test -z "${i//[0-9]}" && echo digits || echo not a number
[[ -n "$i" && -z "${i//[0-9]}" ]] && echo digits || echo not a number

अंगूठे विशेष रूप से man -P 'less +/parameter\/' bashभाग के लिए। हर दिन कुछ नया सीखना। :)
डेविड

@sjas आप \-समस्या को संबोधित करने के लिए नियमित अभिव्यक्ति में आसानी से जोड़ सकते हैं । [0-9\-\.\+]फ़्लोट्स और हस्ताक्षरित संख्याओं के लिए खाते का उपयोग करें ।
user2683246

@sjas ठीक है, मेरी गलती
user2683246

@ सूरजecho $i | python -c $'import sys\ntry:\n float(sys.stdin.read().rstrip())\nexcept:\n sys.exit(1)' && echo yes || echo no
user2683246

9

मेरी समस्या के लिए, मुझे केवल यह सुनिश्चित करने की आवश्यकता थी कि कोई उपयोगकर्ता गलती से कुछ पाठ दर्ज नहीं करता है, इसलिए मैंने इसे सरल और पठनीय रखने की कोशिश की

isNumber() {
    (( $1 )) 2>/dev/null
}

मैन पेज के अनुसार यह बहुत कुछ करता है जो मुझे चाहिए

यदि अभिव्यक्ति का मान गैर-शून्य है, तो रिटर्न स्थिति 0 है

स्ट्रिंग के लिए खराब त्रुटि संदेशों को रोकने के लिए कि "संख्या हो सकती है" मैं त्रुटि आउटपुट को अनदेखा करता हूं

$ (( 2s ))
bash: ((: 2s: value too great for base (error token is "2s")

यह अधिक पसंद है InInteger। लेकिन भयानक धन्यवाद!
नहेल

8

पुराना सवाल है, लेकिन मैं सिर्फ अपने समाधान से निपटना चाहता था। यह किसी भी अजीब खोल चाल की आवश्यकता नहीं है, या हमेशा के लिए आसपास नहीं किया गया है कि कुछ पर भरोसा करते हैं।

if [ -n "$(printf '%s\n' "$var" | sed 's/[0-9]//g')" ]; then
    echo 'is not numeric'
else
    echo 'is numeric'
fi

मूल रूप से यह सिर्फ इनपुट से सभी अंकों को निकालता है, और यदि आप एक गैर-शून्य-लंबाई स्ट्रिंग के साथ छोड़ दिए जाते हैं तो यह एक संख्या नहीं थी।


यह एक खाली के लिए विफल रहता है var
गनीउर्फ_निगौरीफ

या अनुगामी newlines या कुछ की तरह के साथ चर के लिए $'0\n\n\n1\n\n\n2\n\n\n3\n'
गनीउर्फ_निगौरीफ

7

अभी तक टिप्पणी नहीं कर सकता, इसलिए मैं अपना स्वयं का उत्तर जोड़ूंगा, जो बैश पैटर्न मिलान का उपयोग करके ग्लेन जैकमैन के उत्तर का विस्तार है।

मेरी मूल आवश्यकता संख्याओं की पहचान करना और पूर्णांकों और फ़्लोट्स में अंतर करना था। फ़ंक्शन की परिभाषाएँ इसमें कटौती की गईं:

function isInteger() {
    [[ ${1} == ?(-)+([0-9]) ]]
}

function isFloat() {
    [[ ${1} == ?(-)@(+([0-9]).*([0-9])|*([0-9]).+([0-9]))?(E?(-|+)+([0-9])) ]]
}

मैंने अपने पैटर्न को मान्य करने के लिए यूनिट परीक्षण (shUnit2 के साथ) का उपयोग किया:

oneTimeSetUp() {
    int_values="0 123 -0 -123"
    float_values="0.0 0. .0 -0.0 -0. -.0 \
        123.456 123. .456 -123.456 -123. -.456
        123.456E08 123.E08 .456E08 -123.456E08 -123.E08 -.456E08 \
        123.456E+08 123.E+08 .456E+08 -123.456E+08 -123.E+08 -.456E+08 \
        123.456E-08 123.E-08 .456E-08 -123.456E-08 -123.E-08 -.456E-08"
}

testIsIntegerIsFloat() {
    local value
    for value in ${int_values}
    do
        assertTrue "${value} should be tested as integer" "isInteger ${value}"
        assertFalse "${value} should not be tested as float" "isFloat ${value}"
    done

    for value in ${float_values}
    do
        assertTrue "${value} should be tested as float" "isFloat ${value}"
        assertFalse "${value} should not be tested as integer" "isInteger ${value}"
    done

}

नोट्स: आइसोलेट पैटर्न को दशमलव बिंदु ( @(.,)) और ई प्रतीक ( @(Ee)) के बारे में अधिक सहिष्णु होने के लिए संशोधित किया जा सकता है । मेरी इकाई परीक्षण केवल उन मानों का परीक्षण करती है जो पूर्णांक या फ्लोट हैं, लेकिन कोई अमान्य इनपुट नहीं।


मुझे खेद है, समझ में नहीं आया कि कैसे संपादन समारोह का उपयोग करने का इरादा है।
1948 में

6

मैं यह कोशिश करूँगा:

printf "%g" "$var" &> /dev/null
if [[ $? == 0 ]] ; then
    echo "$var is a number."
else
    echo "$var is not a number."
fi

नोट: यह नैन और inf को संख्या के रूप में पहचानता है।


2
या तो डुप्लिकेट, या शायद एक टिप्पणी के रूप में बेहतर अनुकूल है, पिक्सेलबीट का जवाब ( %fशायद वैसे भी बेहतर है)
माइकल

3
पिछले स्टेटस कोड की जाँच करने के बजाय, इसे सिर्फ ifअपने आप में क्यों नहीं रखा ? यही ifकरता है ...if printf "%g" "$var" &> /dev/null; then ...
कैमिलो मार्टिन

3
यह अन्य caveats है। यह खाली स्ट्रिंग को मान्य करेगा, और जैसे तार 'a
गनीउर्फ_निगौर्फ

6

एक स्पष्ट उत्तर पहले से ही दिया गया है @charles Dufy और अन्य द्वारा। शुद्ध बैश समाधान निम्नलिखित का उपयोग करेगा:

string="-12,345"
if [[ "$string" =~ ^-?[0-9]+[.,]?[0-9]*$ ]]
then
    echo $string is a number
else
    echo $string is not a number
fi

यद्यपि वास्तविक संख्याओं के लिए मूलांक बिंदु से पहले संख्या होना अनिवार्य नहीं है ।

फ्लोटिंग नंबरों और वैज्ञानिक संकेतन का अधिक गहन समर्थन प्रदान करने के लिए (सी / फोरट्रान में कई कार्यक्रम या इस तरह से निर्यात करेगा), इस लाइन के लिए एक उपयोगी अतिरिक्त निम्नलिखित होगा:

string="1.2345E-67"
if [[ "$string" =~ ^-?[0-9]*[.,]?[0-9]*[eE]?-?[0-9]+$ ]]
then
    echo $string is a number
else
    echo $string is not a number
fi

इस प्रकार, यदि आप किसी विशिष्ट प्रकार की तलाश कर रहे हैं, तो संख्या के अंतर को समझने का एक तरीका है:

string="-12,345"
if [[ "$string" =~ ^-?[0-9]+$ ]]
then
    echo $string is an integer
elif [[ "$string" =~ ^-?[0-9]*[.,]?[0-9]*$ ]]
then
    echo $string is a float
elif [[ "$string" =~ ^-?[0-9]*[.,]?[0-9]*[eE]-?[0-9]+$ ]]
then
    echo $string is a scientific number
else
    echo $string is not a number
fi

नोट: हम दशमलव और वैज्ञानिक संकेतन के लिए वाक्यात्मक आवश्यकताओं को सूचीबद्ध कर सकते हैं, एक को अल्पविराम बिंदु के रूप में और साथ ही ""। फिर हम यह दावा करेंगे कि इस तरह का केवल एक ही मूलांक होना चाहिए। एक [ईई] फ्लोट में दो +/- संकेत हो सकते हैं। मैंने औलू के काम से कुछ और नियम सीखे हैं, और खराब तारों जैसे '' '-' 'ईई -1' '' 0-0 '' के खिलाफ परीक्षण किया है। यहाँ मेरा रेगेक्स / सबस्ट्रिंग / एक्सपीआर उपकरण हैं जो प्रतीत हो रहा है:

parse_num() {
 local r=`expr "$1" : '.*\([.,]\)' 2>/dev/null | tr -d '\n'` 
 nat='^[+-]?[0-9]+[.,]?$' \
 dot="${1%[.,]*}${r}${1##*[.,]}" \
 float='^[\+\-]?([.,0-9]+[Ee]?[-+]?|)[0-9]+$'
 [[ "$1" == $dot ]] && [[ "$1" =~ $float ]] || [[ "$1" =~ $nat ]]
} # usage: parse_num -123.456

6
[[ $1 =~ ^-?[0-9]+$ ]] && echo "number"

-नकारात्मक संख्याओं को शामिल करना न भूलें !


बैश का न्यूनतम संस्करण क्या है? मैं बस बैश हो जाता हूं: सशर्त बाइनरी ऑपरेटर अपेक्षित बैश: अप्रत्याशित टोकन के पास सिंटैक्स त्रुटि `= ~ '
पॉल हरग्रेव्स

1
@PaHHargreaves =~में कम से कम बैश 3.0 के रूप में मौजूद था।
गिल्स एसओ- बुराई को रोकना '

@PaHHargreaves आपको शायद अपने पहले ऑपरेंड के साथ एक समस्या थी, उदाहरण के लिए बहुत सारे उद्धरण चिह्न या समान
जोशुआ क्लेटन

@JoshuaClayton मैंने संस्करण के बारे में पूछा क्योंकि यह सोलारिस 7 बॉक्स पर बहुत पुराना बैश है, जो अभी भी हमारे पास है और यह समर्थन नहीं करता है = ~
पॉल हरग्रेव्स

6

यह grepदेखने के लिए उपयोग करके प्राप्त किया जा सकता है कि क्या प्रश्न में चर एक विस्तारित नियमित अभिव्यक्ति से मेल खाता है।

टेस्ट पूर्णांक 1120:

yournumber=1120
if echo "$yournumber" | grep -qE '^[0-9]+$'; then
    echo "Valid number."
else
    echo "Error: not a number."
fi

आउटपुट: Valid number.

गैर-पूर्णांक का परीक्षण करें 1120a:

yournumber=1120a
if echo "$yournumber" | grep -qE '^[0-9]+$'; then
    echo "Valid number."
else
    echo "Error: not a number."
fi

आउटपुट: Error: not a number.


व्याख्या

  • grep, -Eस्विच हमें विस्तारित नियमित अभिव्यक्ति का उपयोग करने की अनुमति देता है '^[0-9]+$'। इस रेगुलर एक्सप्रेशन का मतलब है कि वेरिएबल में केवल शुरुआत से लेकर अंत तक नौ के माध्यम से []संख्या 0-9शून्य होना चाहिए और इसमें कम से कम एक वर्ण होना चाहिए ।^$+
  • grep, -qशांत स्विच या नहीं, यह कुछ भी पाता है किसी भी उत्पादन बंद हो जाती है।
  • ifके बाहर निकलने की स्थिति की जाँच करता है grep। एग्जिट स्टेटस का 0मतलब सफलता है और इससे बड़ी चीज का मतलब त्रुटि है। grepआदेश की एक निकास का दर्जा प्राप्त है 0अगर यह एक मैच पाता है और 1जब ऐसा नहीं होता है;

तो यह सब एक साथ, ifपरीक्षण में, हम echoचर करते हैं $yournumberऔर |इसे उस पर पाइप करते हैं grepजिसमें -qस्विच चुपचाप -Eविस्तारित नियमित अभिव्यक्ति '^[0-9]+$'अभिव्यक्ति के साथ मेल खाता है । यदि सफलतापूर्वक मैच मिल गया और यदि ऐसा नहीं हुआ तो बाहर निकलने की स्थिति grepहोगी । यदि सफल मिलान करने के लिए, हम । यदि यह विफल रहा है मैच के लिए, हम ।0grep1echo "Valid number."echo "Error: not a number."


फ़्लोट्स या डबल्स के लिए

हम सिर्फ से नियमित अभिव्यक्ति बदल सकते हैं '^[0-9]+$'करने के लिए '^[0-9]*\.?[0-9]+$'तैरता या डबल्स के लिए।

टेस्ट फ्लोट 1120.01:

yournumber=1120.01
if echo "$yournumber" | grep -qE '^[0-9]*\.?[0-9]+$'; then
    echo "Valid number."
else
    echo "Error: not a number."
fi

आउटपुट: Valid number.

टेस्ट फ्लोट 11.20.01:

yournumber=11.20.01
if echo "$yournumber" | grep -qE '^[0-9]*\.?[0-9]+$'; then
    echo "Valid number."
else
    echo "Error: not a number."
fi

आउटपुट: Error: not a number.


नकारात्मक के लिए

नकारात्मक पूर्णांकों की अनुमति देने के लिए, बस नियमित अभिव्यक्ति को इसमें से बदल '^[0-9]+$'दें '^\-?[0-9]+$'

नकारात्मक फ़्लोट या डबल्स की अनुमति देने के लिए, बस नियमित अभिव्यक्ति को इसमें से बदल '^[0-9]*\.?[0-9]+$'दें '^\-?[0-9]*\.?[0-9]+$'


तुम सही हो, @CharlesDuffy। धन्यवाद। मैंने जवाब साफ किया।
जोसेफ शिह

ठीक है आप फिर से, @CharlesDuffy हैं। फिक्स्ड!
जोसेफ शिह

1
LGTM; उत्तर के रूप में संपादित मेरे +1 है। केवल बातें मैं इस बिंदु पर अलग करना चाहते हैं तो बस, बल्कि शुद्धता (च / ई से राय के मामलों का उपयोग कर रहे हैं [-]के बजाय \-और [.]के बजाय \.एक छोटे से अधिक वर्बोज़ है, लेकिन यह मतलब है कि आपका तार अगर वे बदलने के लिए नहीं है ' एक संदर्भ में उपयोग किया जाता है जहां बैकस्लैश का उपभोग किया जाता है)।
चार्ल्स डॉफी

4

http://tldp.org/LDP/Bash-Beginners-Guide/html/sect_04_03.html

आप बैश के चरित्र वर्गों का भी उपयोग कर सकते हैं।

if [[ $VAR = *[[:digit:]]* ]]; then
 echo "$VAR is numeric"
else
 echo "$VAR is not numeric"
fi

संख्या विज्ञान में फ़्लोटिंग पॉइंट के लिए स्थान, दशमलव बिंदु और "ई" या "ई" शामिल होंगे।

लेकिन, यदि आप एक सी-स्टाइल हेक्स संख्या, अर्थात "0xffff" या "0XFFFF" निर्दिष्ट करते हैं, [[: अंक:]] सही है। यहाँ एक छोटा सा जाल, बैश आपको "0xAZ00" जैसा कुछ करने की अनुमति देता है और फिर भी इसे एक अंक के रूप में गिना जाता है (जीसीसी कंपाइलर्स के कुछ अजीब क्विक से यह नहीं है कि आप 16 के अलावा अन्य आधारों के लिए 0x संकेतन का उपयोग करें ??? )

जब तक कि आपका इनपुट पूरी तरह से अविश्वसनीय न हो, जब तक आप हेक्स संख्या स्वीकार नहीं करना चाहते हैं, तो आप परीक्षण करने से पहले "0x" या "0X" परीक्षण कर सकते हैं। इसके द्वारा पूरा किया जाएगा:

if [[ ${VARIABLE:1:2} = "0x" ]] || [[ ${VARIABLE:1:2} = "0X" ]]; then echo "$VAR is not numeric"; fi

17
[[ $VAR = *[[:digit:]]* ]]सच वापस आ जाएगी अगर चर शामिल एक नंबर, नहीं तो यह है एक पूर्णांक।
बजे ग्लेन जैकमैन

[[ "z3*&" = *[[:digit:]]* ]] && echo "numeric"प्रिंट करता है numeric। बैश संस्करण में परीक्षण किया गया 3.2.25(1)-release
Jadian

1
@ultraswadable, आपका समाधान उन स्ट्रिंग्स का पता लगाता है, जिनमें कम से कम, एक अंक किसी भी अन्य वर्णों से घिरा हुआ (या नहीं) होता है। मैंने नीचा दिखाया।
जद्दन

स्पष्ट रूप से सही दृष्टिकोण इसलिए इसे उल्टा करना है, और उपयोग करना[[ -n $VAR && $VAR != *[^[:digit:]]* ]]
eschwartz

@eschwartz, आपका समाधान नकारात्मक संख्याओं के साथ काम नहीं करता है
एंजेल

4

सबसे सरल तरीका यह जांचना है कि इसमें गैर-अंक वर्ण हैं या नहीं। आप सभी अंकों के अक्षरों को बिना किसी चीज के बदल देते हैं और लंबाई की जांच करते हैं। यदि लंबाई है तो यह संख्या नहीं है।

if [[ ! -n ${input//[0-9]/} ]]; then
    echo "Input Is A Number"
fi

2
नकारात्मक संख्याओं को संभालने के लिए अधिक जटिल दृष्टिकोण की आवश्यकता होगी।
एंडी

... या एक वैकल्पिक सकारात्मक संकेत।
ट्रिपलए

@tripleee मैं आपके दृष्टिकोण को देखना चाहता हूँ यदि आप जानते हैं कि यह कैसे करना है।
एंडी

4

जैसा कि मुझे हाल ही में इसके साथ छेड़छाड़ करनी पड़ी थी और यूनिट की सबसे ज्यादा टेस्ट के साथ कार्ट्टू की वाहवाही मिली थी । मैंने कोड को संशोधित किया और कुछ अन्य समाधान भी जोड़े, परिणाम देखने के लिए इसे स्वयं आज़माएँ:

#!/bin/bash

    # N={0,1,2,3,...} by syntaxerror
function isNaturalNumber()
{
 [[ ${1} =~ ^[0-9]+$ ]]
}
    # Z={...,-2,-1,0,1,2,...} by karttu
function isInteger() 
{
 [[ ${1} == ?(-)+([0-9]) ]]
}
    # Q={...,-½,-¼,0.0,¼,½,...} by karttu
function isFloat() 
{
 [[ ${1} == ?(-)@(+([0-9]).*([0-9])|*([0-9]).+([0-9]))?(E?(-|+)+([0-9])) ]]
}
    # R={...,-1,-½,-¼,0.E+n,¼,½,1,...}
function isNumber()
{
 isNaturalNumber $1 || isInteger $1 || isFloat $1
}

bools=("TRUE" "FALSE")
int_values="0 123 -0 -123"
float_values="0.0 0. .0 -0.0 -0. -.0 \
    123.456 123. .456 -123.456 -123. -.456 \
    123.456E08 123.E08 .456E08 -123.456E08 -123.E08 -.456E08 \
    123.456E+08 123.E+08 .456E+08 -123.456E+08 -123.E+08 -.456E+08 \
    123.456E-08 123.E-08 .456E-08 -123.456E-08 -123.E-08 -.456E-08"
false_values="blah meh mooh blah5 67mooh a123bc"

for value in ${int_values} ${float_values} ${false_values}
do
    printf "  %5s=%-30s" $(isNaturalNumber $value) ${bools[$?]} $(printf "isNaturalNumber(%s)" $value)
    printf "%5s=%-24s" $(isInteger $value) ${bools[$?]} $(printf "isInteger(%s)" $value)
    printf "%5s=%-24s" $(isFloat $value) ${bools[$?]} $(printf "isFloat(%s)" $value)
    printf "%5s=%-24s\n" $(isNumber $value) ${bools[$?]} $(printf "isNumber(%s)" $value)
done

तो ISNUMBER () डैश, अल्पविराम और घातीय संकेतन शामिल है और इसलिए पूर्णांकों और तैरता जहां दूसरी ओर पर सही रिटर्न isFloat () पूर्णांक मूल्यों और पर रिटर्न गलत isInteger () वैसे ही तैरता पर FALSE देता है। एक लाइनर के रूप में आपकी सुविधा के लिए:

isNaturalNumber() { [[ ${1} =~ ^[0-9]+$ ]]; }
isInteger() { [[ ${1} == ?(-)+([0-9]) ]]; }
isFloat() { [[ ${1} == ?(-)@(+([0-9]).*([0-9])|*([0-9]).+([0-9]))?(E?(-|+)+([0-9])) ]]; }
isNumber() { isNaturalNumber $1 || isInteger $1 || isFloat $1; }

व्यक्तिगत रूप से मैं functionकीवर्ड को हटा दूँगा क्योंकि यह कुछ भी उपयोगी नहीं है। इसके अलावा, मैं रिटर्न वैल्यू की उपयोगिता के बारे में निश्चित नहीं हूं। जब तक अन्यथा निर्दिष्ट नहीं किया जाता है, तब तक फ़ंक्शन अंतिम कमांड की निकास स्थिति को वापस कर देगा, इसलिए आपको returnस्वयं कुछ भी करने की आवश्यकता नहीं है ।
टॉम फेनेच

अच्छा, वास्तव में returnएस भ्रमित कर रहे हैं और इसे कम पठनीय बनाते हैं। functionकीवर्ड का उपयोग करना या न करना अधिक व्यक्तिगत स्वाद का सवाल है, कम से कम मैंने कुछ जगह बचाने के लिए उन्हें एक लाइनर्स से हटा दिया। धन्यवाद।
3ronco

मत भूलो कि एक-लाइन संस्करणों के लिए परीक्षणों के बाद अर्धविराम की आवश्यकता है।
टॉम फेनेच

2
isNumber किसी भी स्ट्रिंग पर 'सही' लौटाएगा, जिसमें एक नंबर है।
DrStrangepork

@DrStrangepork वास्तव में, मेरे झूठे_वायु सरणी उस मामले को याद कर रहे हैं। मैं इस पर गौर करूंगा। संकेत के लिए धन्यवाद।
3ronco

4

मैं expr का उपयोग करता हूं । यदि आप गैर-संख्यात्मक मान में शून्य जोड़ने का प्रयास करते हैं तो यह एक गैर-शून्य देता है:

if expr -- "$number" + 0 > /dev/null 2>&1
then
    echo "$number is a number"
else
    echo "$number isn't a number"
fi

यदि आपको गैर-पूर्णांक की आवश्यकता है, तो बीसी का उपयोग करना संभव हो सकता है , लेकिन मुझे विश्वास नहीं है कि bcइसमें समान व्यवहार है। गैर-संख्या में शून्य जोड़ने से आपको शून्य मिलता है और यह शून्य का मान भी लौटाता है। हो सकता है आप को जोड़ सकते हैं bcऔर expr। में bcशून्य जोड़ने के लिए उपयोग करें$number । यदि उत्तर है 0, तो exprसत्यापित करने का प्रयास करें कि $numberशून्य नहीं है।


1
यह बल्कि बुरा है। इसे थोड़ा बेहतर बनाने के लिए आपको उपयोग करना चाहिए expr -- "$number" + 0; फिर भी यह अभी भी दिखावा करेगा 0 isn't a number। प्रेषक man expr:Exit status is 0 if EXPRESSION is neither null nor 0, 1 if EXPRESSION is null or 0,
gniourf_gniourf

3

मुझे अल्बर्टो ज़ाकाग्नि का जवाब पसंद है।

if [ "$var" -eq "$var" ] 2>/dev/null; then

महत्वपूर्ण पूर्वापेक्षाएँ: - कोई उपधारा नहीं निकाली गई - कोई आरई पार्सर्स नहीं लगाया गया - अधिकांश शेल एप्लिकेशन वास्तविक संख्याओं का उपयोग नहीं करते हैं

लेकिन अगर $varजटिल है (जैसे एक साहचर्य सरणी पहुंच), और यदि संख्या एक गैर-नकारात्मक पूर्णांक (अधिकांश उपयोग-मामले) होगी, तो यह संभवतः अधिक कुशल है?

if [ "$var" -ge 0 ] 2> /dev/null; then ..

2

मैं उल्लिखित अन्य उत्तरों के रूप में प्रिंटफ का उपयोग करता हूं, यदि आप प्रारूप स्ट्रिंग "% f" या "% i" की आपूर्ति करते हैं तो प्रिंटफ आपके लिए चेकिंग करेगा। चेकों पर लगाम लगाने की तुलना में आसान है, वाक्यविन्यास सरल और छोटा है और प्रिंटफ सर्वव्यापी है। तो मेरी राय में यह एक सभ्य विकल्प है - आप चीजों की एक श्रृंखला की जांच करने के लिए निम्नलिखित विचार का भी उपयोग कर सकते हैं, न केवल जाँच संख्याओं के लिए उपयोगी है।

declare  -r CHECK_FLOAT="%f"  
declare  -r CHECK_INTEGER="%i"  

 ## <arg 1> Number - Number to check  
 ## <arg 2> String - Number type to check  
 ## <arg 3> String - Error message  
function check_number() { 
  local NUMBER="${1}" 
  local NUMBER_TYPE="${2}" 
  local ERROR_MESG="${3}"
  local -i PASS=1 
  local -i FAIL=0   
  case "${NUMBER_TYPE}" in 
    "${CHECK_FLOAT}") 
        if ((! $(printf "${CHECK_FLOAT}" "${NUMBER}" &>/dev/random;echo $?))); then 
           echo "${PASS}"
        else 
           echo "${ERROR_MESG}" 1>&2
           echo "${FAIL}"
        fi 
        ;;                 
    "${CHECK_INTEGER}") 
        if ((! $(printf "${CHECK_INTEGER}" "${NUMBER}" &>/dev/random;echo $?))); then 
           echo "${PASS}"
        else 
           echo "${ERROR_MESG}" 1>&2
           echo "${FAIL}"
        fi 
        ;;                 
                     *) 
        echo "Invalid number type format: ${NUMBER_TYPE} to check_number()." 1>&2
        echo "${FAIL}"
        ;;                 
   esac
} 

>$ var=45

>$ (($(check_number $var "${CHECK_INTEGER}" "Error: Found $var - An integer is required."))) && { echo "$var+5" | bc; }


2

नियमित अभिव्यक्ति बनाम पैरामीटर विस्तार

जैसा चार्ल्स डफी जवाब काम है, लेकिन केवल उपयोग नियमित अभिव्यक्ति , और मुझे पता है कि यह धीमा है, मैं केवल उपयोग करके एक और रास्ता दिखाना चाहता हूंपैरामीटर विस्तार :

केवल सकारात्मक पूर्णांक के लिए:

is_num() { [ "$1" ] && [ -z "${1//[0-9]}" ] ;}

पूर्णांकों के लिए:

is_num() { 
    local chk=${1#[+-]};
    [ "$chk" ] && [ -z "${chk//[0-9]}" ]
}

फिर तैरने के लिए:

is_num() { 
    local chk=${1#[+-]};
    chk=${chk/.}
    [ "$chk" ] && [ -z "${chk//[0-9]}" ]
}

प्रारंभिक अनुरोध से मेल खाने के लिए:

set -- "foo bar"
is_num "$1" && VAR=$1 || echo "need a number"
need a number

set -- "+3.141592"
is_num "$1" && VAR=$1 || echo "need a number"

echo $VAR
+3.141592

अब थोड़ी तुलना:

चार्ल्स डफी के उत्तर पर आधारित एक ही जाँच है :

cdIs_num() { 
    local re='^[+-]?[0-9]+([.][0-9]+)?$';
    [[ $1 =~ $re ]]
}

कुछ परीक्षण:

if is_num foo;then echo It\'s a number ;else echo Not a number;fi
Not a number
if cdIs_num foo;then echo It\'s a number ;else echo Not a number;fi
Not a number
if is_num 25;then echo It\'s a number ;else echo Not a number;fi
It's a number
if cdIs_num 25;then echo It\'s a number ;else echo Not a number;fi
It's a number
if is_num 3+4;then echo It\'s a number ;else echo Not a number;fi
Not a number
if cdIs_num 3+4;then echo It\'s a number ;else echo Not a number;fi
Not a number
if is_num 3.1415;then echo It\'s a number ;else echo Not a number;fi
It's a number
if cdIs_num 3.1415;then echo It\'s a number ;else echo Not a number;fi
It's a number

हॉ, वह ठीक है। अब यह सब करने में मुझे कितना समय लगेगा (मेरी रास्पबेरी पाई पर):

time for i in {1..1000};do is_num +3.14159265;done
real    0m2.476s
user    0m1.235s
sys     0m0.000s

फिर नियमित अभिव्यक्तियों के साथ:

time for i in {1..1000};do cdIs_num +3.14159265;done
real    0m4.363s
user    0m2.168s
sys     0m0.000s

मैं सहमत हूं, वैसे भी, मैं रेगेक्स का उपयोग नहीं करना पसंद करता हूं, जब मैं पैरामीटर विस्तार का उपयोग कर सकता हूं ... आरई का दुरुपयोग बैश स्क्रिप्ट को धीमा कर देगा
एफ। होरी

उत्तर संपादित: कोई ज़रूरत नहीं है extglob(और थोड़ा तेज़)!
एफ। होरी

@CharlesDuffy, मेरी रास्पबेरी पाई पर, 1000 पुनरावृत्ति मेरे संस्करण के साथ 2,5sec और आपके संस्करण के साथ 4,4sec लेगी!
एफ। होरी

उससे बहस नहीं कर सकते। Uffy
चार्ल्स डफी

1

नकारात्मक संख्याओं को पकड़ने के लिए:

if [[ $1 == ?(-)+([0-9.]) ]]
    then
    echo number
else
    echo not a number
fi

इसके अलावा, इसके लिए पहले विस्तारित ग्लोबिंग को सक्षम करना होगा। यह एक बैश-केवल सुविधा है जो डिफ़ॉल्ट रूप से अक्षम है।
ट्रिपलए

@tripleee विस्तारित ग्लोबिंग == या! = When the ‘==’ and ‘!=’ operators are used, the string to the right of the operator is considered a pattern and matched according to the rules described below in Pattern Matching, as if the extglob shell option were enabled. gnu.org/software/bash/manual/bashref.html#index-_005b_005b
Badr Elmers

@BadrElmers अपडेट के लिए धन्यवाद। यह एक नया व्यवहार प्रतीत होता है जो मेरे बैश 3.2.57 (MacOS Mojave) में सच नहीं है। मैं देख रहा हूँ कि यह काम करता है जैसा कि आप 4.4 में वर्णन करते हैं।
ट्रिपल

1

आप "लेट" का उपयोग इस तरह से कर सकते हैं:

[ ~]$ var=1
[ ~]$ let $var && echo "It's a number" || echo "It's not a number"
It\'s a number
[ ~]$ var=01
[ ~]$ let $var && echo "It's a number" || echo "It's not a number"
It\'s a number
[ ~]$ var=toto
[ ~]$ let $var && echo "It's a number" || echo "It's not a number"
It\'s not a number
[ ~]$ 

लेकिन मैं इस धागे में कुछ जवाबों की तरह "= ~" बैश 3+ ऑपरेटर का उपयोग करना पसंद करता हूं।


5
यह बहुत खतरनाक है। खोल में अनवस्थित अंकगणित का मूल्यांकन न करें। इसे पहले किसी और तरीके से मान्य किया जाना चाहिए।
ओरमज

1
printf '%b' "-123\nABC" | tr '[:space:]' '_' | grep -q '^-\?[[:digit:]]\+$' && echo "Integer." || echo "NOT integer."

-\?यदि आप ऋणात्मक पूर्णांक स्वीकार नहीं करते हैं, तो grep मिलान पैटर्न को निकालें ।


2
स्पष्टीकरण की कमी के लिए डाउनवोट। यह कैसे काम करता है? यह जटिल और भंगुर दिखता है, और यह स्पष्ट नहीं है कि वास्तव में क्या इनपुट स्वीकार करेगा। (उदाहरण के लिए, आवश्यक रूप से रिक्त स्थान को हटा रहा है? क्यों? यह कहेगा कि एम्बेडेड स्पेस वाला एक नंबर एक मान्य संख्या है, जो वांछनीय हो सकती है।)
tripleee

1

क्या यहाँ एक नियमित अभिव्यक्ति के साथ एक ही चीज़ थी जो पूरे भाग का परीक्षण करती है और एक दशमलव के साथ अलग हो जाती है।

re="^[0-9]*[.]{0,1}[0-9]*$"

if [[ $1 =~ $re ]] 
then
   echo "is numeric"
else
  echo "Naahh, not numeric"
fi

क्या आप बता सकते हैं कि आपका उत्तर मूल रूप से अन्य पुराने उत्तरों, चार्ल्स डफी के उत्तर से अलग क्यों है? खैर, आपका जवाब वास्तव में टूट गया है क्योंकि यह एक एकल अवधि को मान्य करता है.
gniourf_gniourf

यहाँ एकल अवधि को समझने के लिए सुनिश्चित नहीं है ... यह एक या शून्य अवधि की उम्मीद है .... लेकिन मौलिक रूप से कुछ भी सही नहीं है, बस रीडगेक्स को पढ़ना आसान है।
जेरोम

यह भी * का उपयोग वास्तविक दुनिया के मामलों से मेल खाना चाहिए
जेरोम

बात यह है कि आप खाली स्ट्रिंग a=''और स्ट्रिंग का मिलान कर रहे हैं , जिसमें केवल एक अवधि शामिल है, a='.'इसलिए आपका कोड थोड़ा टूटा हुआ है ...
gniourf_gniourf

0

मैं निम्नलिखित (पूर्णांक के लिए) का उपयोग करता हूं:

## ##### constants
##
## __TRUE - true (0)
## __FALSE - false (1)
##
typeset -r __TRUE=0
typeset -r __FALSE=1

## --------------------------------------
## isNumber
## check if a value is an integer 
## usage: isNumber testValue 
## returns: ${__TRUE} - testValue is a number else not
##
function isNumber {
  typeset TESTVAR="$(echo "$1" | sed 's/[0-9]*//g' )"
  [ "${TESTVAR}"x = ""x ] && return ${__TRUE} || return ${__FALSE}
}

isNumber $1 
if [ $? -eq ${__TRUE} ] ; then
  print "is a number"
fi

लगभग सही (आप खाली स्ट्रिंग को स्वीकार कर रहे हैं) लेकिन मोटे तौर पर मोटापे के बिंदु पर जटिल है।
गिल्स एसओ- बुराई को रोकना '

2
गलत: आप स्वीकार कर रहे हैं -n, इत्यादि (के कारण echo), और आप नए संस्करण (क्योंकि $(...)) की अनुगामी के साथ चर स्वीकार कर रहे हैं । और वैसे, printएक वैध शेल कमांड नहीं है।
गनीउर्फ_निगौर्फ

0

मैंने अल्ट्रावेलब्लेड की रेसिपी को आजमाया क्योंकि यह मेरे लिए सबसे अधिक व्यावहारिक था, और यह काम नहीं कर सका। अंत में, मैंने एक और तरीका तैयार किया, हालांकि पैरामीटर प्रतिस्थापन में दूसरों के रूप में, इस बार रेगेक्स प्रतिस्थापन के साथ:

[[ "${var//*([[:digit:]])}" ]]; && echo "$var is not numeric" || echo "$var is numeric"

यह प्रत्येक को हटाता है: $ var में अंक: वर्ग चरित्र और जाँच करता है कि क्या हम एक खाली स्ट्रिंग के साथ छोड़ दिए गए हैं, जिसका अर्थ है कि मूल केवल संख्या थी।

मैं इसके बारे में जो पसंद करता हूं, वह इसका छोटा पदचिह्न और लचीलापन है। इस रूप में यह केवल गैर-सीमांकित, आधार 10 पूर्णांक के लिए काम करता है, हालांकि निश्चित रूप से आप इसे अन्य आवश्यकताओं के अनुरूप करने के लिए पैटर्न मिलान का उपयोग कर सकते हैं।


Mrucci के समाधान को पढ़ना, यह लगभग मेरी तरह ही दिखता है, लेकिन "sed शैली" के बजाय नियमित स्ट्रिंग प्रतिस्थापन का उपयोग करना। दोनों पैटर्न मिलान के लिए समान नियमों का उपयोग करते हैं और हैं, AFAIK, विनिमेय समाधान।
अता

sedPOSIX है, जबकि आपका समाधान है bash। दोनों के अपने उपयोग हैं
v010dya

0

त्वरित और गंदा: मुझे पता है कि यह सबसे सुंदर तरीका नहीं है, लेकिन मैंने आमतौर पर इसमें एक शून्य जोड़ दिया और परिणाम का परीक्षण किया। इस तरह:

function isInteger {
  [ $(($1+0)) != 0 ] && echo "$1 is a number" || echo "$1 is not a number"
 }

x=1;      isInteger $x
x="1";    isInteger $x
x="joe";  isInteger $x
x=0x16 ;  isInteger $x
x=-32674; isInteger $x   

यदि $ 1 पूर्णांक नहीं है तो $ (($ 1 + 0)) 0 या बम लौटाएगा। उदाहरण के लिए:

function zipIt  { # quick zip - unless the 1st parameter is a number
  ERROR="not a valid number. " 
  if [ $(($1+0)) != 0 ] ; then  # isInteger($1) 
      echo " backing up files changed in the last $1 days."
      OUT="zipIt-$1-day.tgz" 
      find . -mtime -$1 -type f -print0 | xargs -0 tar cvzf $OUT 
      return 1
  fi
    showError $ERROR
}

नोट: मुझे लगता है कि मैंने कभी भी फ़्लोट्स या मिश्रित प्रकारों की जांच करने के लिए नहीं सोचा था जो पूरे स्क्रिप्ट को बम बना देगा ... मेरे मामले में, मैं नहीं चाहता था कि यह किसी भी और आगे बढ़े। मैं mrucci के समाधान और डफी के रेगेक्स के साथ खेलने जा रहा हूं - वे बैश ढांचे के भीतर सबसे मजबूत लगते हैं ...


4
यह अंकगणितीय अभिव्यक्तियों को स्वीकार करता है 1+1, लेकिन अग्रणी 0s के साथ कुछ सकारात्मक पूर्णांकों को अस्वीकार करता है (क्योंकि 08एक अमान्य अष्टक स्थिरांक है)।
गिलेस एसओ-

2
इसके अन्य मुद्दे भी हैं: 0एक संख्या नहीं है, और यह मनमाने ढंग से कोड इंजेक्शन के अधीन है, इसे आज़माएं isInteger 'a[$(ls)]':। ओह।
gniourf_gniourf

1
और का विस्तार $((...))निर्विवाद है, एक संख्यात्मक IFS=123इसे बदल देगा।
इसहाक
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.