/ bin / dash: ตรวจสอบว่า $ 1 เป็นตัวเลขหรือไม่


12

อะไรจะเป็นวิธีที่ดีที่สุดในการตรวจสอบว่า $ 1 เป็นจำนวนเต็มใน / bin / dash หรือไม่

ในทุบตีฉันสามารถทำ:

[[ $1 =~ ^([0-9]+)$ ]]

แต่ดูเหมือนจะไม่เป็นไปตาม POSIX และ dash ไม่สนับสนุนสิ่งนั้น

คำตอบ:


12

ตรวจจับจำนวนเต็มบวกหรือลบและทำงานภายใต้dashและเป็น POSIX ต่อไปนี้:

ตัวเลือกที่ 1

echo "$1" | grep -Eq '^[+-]?[0-9]+$' && echo "It's an integer"

ตัวเลือก 2

case "${1#[+-]}" in
    ''|*[!0-9]*)
        echo "Not an integer" ;;
    *)
        echo "Integer" ;;
esac

หรือด้วยการใช้:คำสั่ง (nop) เล็กน้อย:

! case ${1#[+-]} in *[!0-9]*) :;; ?*) ! :;; esac && echo Integer

5
เกิดอะไรขึ้นถ้าสตริงมีการขึ้นบรรทัดใหม่ foo\n123\nbarไม่ใช่จำนวนเต็ม แต่จะผ่านการทดสอบนี้
godlygeek

3
รุ่น grep นั่นคือ รุ่นเคสดูถูกต้อง
godlygeek

5

ไม่ว่าจะเป็นdash, bash, ksh, zsh, POSIX shหรือposh( "a reimplementation ของบอร์นเชลล์" sh ); การcaseก่อสร้างนั้นมีอยู่อย่างกว้างขวางและเชื่อถือได้มากที่สุด:

case $1 in (*[!0-9]*|"") false ;; (*) true ;; esac

คุณทดสอบสิ่งนี้ภายใต้dashหรือไม่? การทำงานสำหรับฉันภายใต้แต่ไม่bash dash
John1024

ใช่ฉันทดสอบในระบบของฉันด้วยdashเช่นกัน เพื่อสอบถามผลลัพธ์ที่ฉันเพิ่มecho $?หลังจากคำสั่ง case
Janis

ฉันทำแบบเดียวกัน (เดเบียนเสถียร) แต่ไม่มีความสุข สำหรับตัวอย่างที่สมบูรณ์ที่ทำงานสำหรับฉันภายใต้เส้นประของฉันฉันเห็นตัวเลือกที่ 2
John1024

อืมฉันไม่มีกระสุน bourne ดั้งเดิมทดสอบ เอกสารที่ฉันตรวจสอบเกี่ยวกับ "คุณสมบัติ [ใน ksh] ไม่ได้อยู่ในเปลือก bourne" อย่างน้อยก็ไม่ได้พูดถึงมันดังนั้นฉันคิดว่ามันอยู่ที่นั่น ไม่มี? - จากนั้นไม่ใส่วงเล็บนำ - OTOH posh("การใช้งานใหม่ของบอร์นเชลล์") ก็ไม่มีปัญหาในการแก้ปัญหาดังกล่าว
Janis

1
@mikeserv; มีเหตุผลหลายประการที่ผมใช้วงเล็บจับคู่เสมอในมีcase; เหตุผลข้อหนึ่งคือข้อผิดพลาดที่คุณอธิบายอีกข้อหนึ่งที่ในโปรแกรมแก้ไขที่มีคุณสมบัติที่ต้องพึ่งพาวงเล็บที่ตรงกัน (vim) จะให้การสนับสนุนที่ดีกว่ามาก - WRT poshเป็น POSIX; ดีอ้างจากหน้าคนที่ฉันให้คำแนะนำอย่างอื่น แต่อย่างใดอย่างหนึ่งไม่สามารถพึ่งพางบนอกระบบดังกล่าวฉันเดา เชลล์ bourne เก่านั้นไม่สำคัญเท่าไรตอนนี้เราอยู่ในยุค POSIX
Janis

1

คุณสามารถใช้การ-eqทดสอบกับสตริงด้วยตัวเอง:

$ dash -c 'a="a"; if [ "$a" -eq "$a" ] ; then echo number; else echo not a number; fi' 
dash: 1: [: Illegal number: a
not a number
$ dash -c 'a="0xa"; if [ "$a" -eq "$a" ] ; then echo number; else echo not a number; fi'
dash: 1: [: Illegal number: 0xa
not a number
$ dash -c 'a="-1"; if [ "$a" -eq "$a" ] ; then echo number; else echo not a number; fi'
number

หากข้อความแสดงข้อผิดพลาดเป็นปัญหาให้เปลี่ยนเส้นทางข้อผิดพลาดไปที่/dev/null:

$ dash -c 'a="0xa"; [ "$a" -eq "$a" ] 2>/dev/null|| echo no'
no

1
มันก็จะบอกว่า" 023 "เป็นตัวเลข โปรดทราบว่ามันทำงานร่วมกับประ แต่ไม่ใช่เปลือก POSIX อื่น ๆ ทั้งหมดเป็นพฤติกรรมที่ไม่ได้ระบุหากตัวถูกดำเนินการเป็นจำนวนเต็มทศนิยมทศนิยม เช่นกับ ksh มันจะบอกว่าSHLVLหรือ1+1เป็นตัวเลข
Stéphane Chazelas

0

ลองใช้เป็นส่วนขยายเลขคณิตและดูว่าใช้งานได้หรือไม่ ที่จริงแล้วคุณต้องเข้มงวดกว่านั้นเล็กน้อยเนื่องจากการขยายเลขคณิตจะไม่สนใจช่องว่างนำหน้าและส่วนท้าย ดังนั้นการขยายเลขคณิตและตรวจสอบให้แน่ใจว่าผลลัพธ์ที่ขยายเพิ่มนั้นตรงกับตัวแปรดั้งเดิมอย่างแน่นอน

check_if_number()
{
    if [ "$1" = "$((${1}))" ] 2>/dev/null; then
        echo "Number!"
    else
        echo "not a number"
    fi
}

นอกจากนี้ยังจะยอมรับตัวเลขติดลบ - $((${1} >= 0))ถ้าคุณจริงๆหมายถึงจะไม่รวมพวกเขาเพิ่มการตรวจสอบพิเศษสำหรับ


1
เส้นประไม่มี[[
เกล็นแจ็คแมน

@glennjackman อ๊ะ มันมี$(( ... ))หรือไม่ ถ้าเป็นเช่นนั้นคำตอบของฉันยังควรถูกต้องอย่างมีนัยสำคัญฉันต้องเพิ่มข้อความพิเศษ
godlygeek

มันเป็นคำตอบของคุณ: ไปหา
เกล็นแจ็คแมน

ดูเหมือนว่าจะเป็นเช่นนั้นดังนั้นเวอร์ชันที่อัปเดตของฉันควรทำเคล็ดลับ ฉันไม่มีความรีบเร่งที่จะทดสอบมัน - ดังนั้นให้ฉันรู้ว่าฉันพลาดอะไรไปหรือเปล่า
godlygeek

ฉันลอง: check_if_number 1.2และฟังก์ชั่นคืน: dash: 3: arithmetic expression: expecting EOF: "1.2"
John1024

0

อาจจะด้วยexpr?

if expr match "$1" '^\([0-9]\+\)$' > /dev/null; then
  echo "integer"
else 
  echo "non-integer"
fi

ค่าmatchมิได้\+มี POSIX มันก็จะบอกว่า 0 ไม่ใช่ตัวเลข คุณต้องการexpr "x$1" : 'x[0-9]\{1,\}$'
Stéphane Chazelas

0

ในระบบ POSIX คุณสามารถใช้expr :

$ a=a
$ expr "$a" - 0 >/dev/null 2>&1
$ [ "$?" -lt 2 ] && echo Integer || echo Not Integer

มันจะบอกว่า 0 ไม่ใช่จำนวนเต็ม (และบอกว่า -12 เป็นวิธีที่ bash ของ OP จะปฏิเสธ) exprการใช้งานบางอย่างจะบอกว่า 9999999999999999999 ไม่ใช่จำนวนเต็ม POSIX ไม่รับประกันว่าจะใช้งานได้ ในทางปฏิบัติในระบบ GNU เป็นอย่างน้อยมันจะบอกว่า "length" เป็นจำนวนเต็ม
Stéphane Chazelas

ในการทดสอบของฉันมันทำงานได้อย่างน้อยใน Debian และ OSX มันบอกว่าจำนวนเต็มสำหรับ 0 Posix ให้แน่ใจว่า $ a จะต้องเป็นนิพจน์ที่ถูกต้อง (จำนวนเต็ม) สำหรับ expr do เลขคณิต
cuonglm

โอ้ใช่ขอโทษฉันมองข้ามการทดสอบของคุณสำหรับ $? <2 ยังคงexpr 9999999999999999999 + 0ให้ฉันสถานะ 3 และทางออกexpr -12 + 0และexpr length + 0ให้ฉันสถานะ 0 ทางออกกับ GNU expr ( + stringกองกำลังstringที่จะได้รับการพิจารณาเป็นสตริงกับ GNU expr. expr "$a" - 0จะทำงานได้ดี)
Stéphane Chazelas

@ StéphaneChazelas: โอ้ใช่อัปเดตคำตอบของฉัน ฉันคิดว่า-12เป็นจำนวนเต็มที่ถูกต้องและ9999999999999999999ให้มากเกินไป
cuonglm

0

นี่เป็นฟังก์ชั่นเรียบง่ายโดยใช้วิธีการเดียวกับคำตอบของmuru :

IsInteger()      # usage: IsInteger string
{               #  returns: flag
        [ "$1" -eq "$1" ] 2> /dev/null
}

ตัวอย่าง:

p= n=2a3; IsInteger $n || p="n't" ; printf "'%s' is%s an integer\n" "$n" "$p"
p= n=23;  IsInteger $n || p="n't" ; printf "'%s' is%s an integer\n" "$n" "$p"

เอาท์พุท:

'2a3' isn't an integer
'23' is an integer
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.