มีความแตกต่างที่สำคัญเมื่อเปรียบเทียบตัวแปรเป็นสตริงหรือเป็น int


22

จากความอยากรู้เมื่อทำการเปรียบเทียบตัวแปรทุบตี (ความคุ้มค่าเป็นinteger) ก็เป็นไปได้ที่จะทดสอบกับค่าที่กำหนดไว้ล่วงหน้าบางส่วนประกาศว่าจะเป็นหรือเป็นintstring

สคริปต์ตัวอย่าง :

#!/bin/bash
f1()
{
        [ "$1" == "1" ] && echo "$FUNCNAME: \"1\" compared as string"
}

f2()
{
        [[ "$1" -eq 1 ]] && echo "$FUNCNAME: \"1\" compared as int"
}

f1 $1
f2 $1

ผลผลิต :

$  ./param.sh 1
f1: "1" compared as string
f2: "1" compared as int

และ

$  ./param.sh blah
$

ฟังก์ชั่นทั้งสองทำงานในลักษณะเดียวกันฉันจึงสงสัยว่ามีวิธีที่ต้องการหรือไม่เมื่อตรวจสอบตัวแปรจำนวนเต็ม? ฉันจะไปตรวจสอบintกับintมันเพราะมันเข้มงวดมากขึ้น แต่ฉันก็สงสัยว่ามีการดึงกลับมาทำด้วยstringหรือไม่?

ในกรณีf2()นี้มีความเข้มงวดมากขึ้นเกี่ยวกับการเปรียบเทียบเช่นการส่งค่าทศนิยมจะทำให้แตกในขณะที่f1()จะไม่มีปัญหา


โปรดทราบว่า Bash ไม่มีประเภทข้อมูล Integer จริงๆ โดยพื้นฐานแล้วคุณสามารถบอกใบ้ Bash ให้ถือว่า String เป็นจำนวนเต็ม
helpermethod

คำตอบ:


18

ใช่ความแตกต่างมากมาย ตัวอย่างเช่น=ตรวจสอบความเท่าเทียมกันของสตริงที่แน่นอน แต่-eqประเมินทั้งสองนิพจน์ทางคณิตศาสตร์ก่อนตรวจสอบความเท่าเทียมกัน:

$ [ " 1 " -eq 1 ] && echo equal || echo not
equal
$ [ " 1 " = 1 ] && echo equal || echo not
not

$ [ +1 -eq 1 ] && echo equal || echo not
equal
$ [ +1 = 1 ] && echo equal || echo not
not

$ [ "0+1" -eq 1 ] && echo equal || echo not
equal
$ [ "0+1" = 1 ] && echo equal || echo not
not

นอกจากนี้สตริงว่างเกิดขึ้นจะเป็นตัวเลขเท่ากับศูนย์:

$ [ "" -eq 0 ] && echo equal || echo not
equal
$ [ "" = 0 ] && echo equal || echo not
not

และความแตกต่างคลาสอื่นทั้งหมดจะปรากฏขึ้นเมื่อคุณนำโอเปอเรเตอร์การเปรียบเทียบเข้ามา - พิจารณา<เทียบ-ltกับตัวอย่างเช่น:

$ [[ 2 -lt 10 ]] && echo less || echo not
less
$ [[ 2 < 10 ]] && echo less || echo not
not

นี่เป็นเพราะสตริง "2" เป็นตัวอักษรหลังสตริง "10" (ตั้งแต่ 1 มาก่อน 2) แต่ตัวเลข "2" นั้นน้อยกว่าตัวเลข "10"


2
อย่าลืมว่ายังมี(( ... ))การดำเนินการตัวเลข (( " 1 " == 1 )) && echo yes || echo noผลลัพธ์ในyes
Patrick

7

จำนวนเต็มเปรียบเทียบกับการเปรียบเทียบสตริงกลายเป็นสิ่งสำคัญที่สุดเมื่อคุณเปรียบเทียบมากกว่าหรือน้อยกว่า:

#!/bin/bash

eleven=11
nine=9

[[ $nine < $eleven ]] && echo string   # fail

[[ "$nine" -lt "$eleven" ]] && echo integer # pass

อันแรกล้มเหลวเพราะ 9 มาหลังจาก 11 เมื่อเรียงตามพจนานุกรม

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

[ "" -lt 11 ]

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

[ "" \< 11 ]

หมายเหตุภายในคู่วงเล็บ""จะแต่ไม่-eq 0== 0


1
ใน bash นั้นไม่จำเป็นอย่างยิ่งที่จะต้องอ้างอิงตัวแปรภายในเครื่องหมายวงเล็บคู่: builtin [[นั้นฉลาดพอที่จะจดจำว่าตัวแปรอยู่ที่ไหนและจะไม่ถูกหลอกโดยตัวแปรว่างเปล่า วงเล็บเดียว ( [) ไม่มีคุณสมบัตินี้และต้องมีเครื่องหมายคำพูด
เกล็นแจ็คแมน

@glennjackman ไม่เคยสังเกตมาก่อนว่า [[ -lt 11 ]]เป็นข้อผิดพลาด แต่nothing=; [[ $nothing -lt 11 ]]ไม่ใช่ ฉันได้ทำใหม่ย่อหน้าสุดท้ายเล็กน้อย
goldilocks

2

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

$ b=234
$ time for ((a=1;a<1000000;a++)); do [[ $b = "234" ]]; done

real    0m13.008s
user    0m12.677s
sys 0m0.312s

$ time for ((a=1;a<1000000;a++)); do [[ $b -eq 234 ]]; done

real    0m10.266s
user    0m9.657s
sys 0m0.572s

เมื่อพิจารณาว่าพวกเขาทำสิ่งต่าง ๆ ฉันจะบอกว่าการแสดงนั้นไม่เกี่ยวข้อง - คุณต้องใช้สิ่งที่คุณต้องการ
godlygeek

@godlygeek การเปรียบเทียบความเท่าเทียมกันของตัวแปรสามารถทำได้ทั้งสองทาง "-eq" เร็วขึ้น
Emmanuel

พวกเขาทดสอบความหมายที่แตกต่างกันของความเท่าเทียมกัน หากคุณต้องการตอบคำถาม "ตัวแปรนี้มีสตริง 123 ที่แน่นอนหรือไม่" คุณสามารถใช้งานได้เท่านั้น=เนื่องจากการใช้-eqจะตรงกับ "+123" เช่นกัน ถ้าคุณอยากจะรู้ว่า "ไม่ตัวแปรนี้เมื่อประเมินว่าการแสดงออกทางคณิตศาสตร์เปรียบเทียบเท่ากับ 123" -eqคุณสามารถใช้เท่านั้น ครั้งเดียวที่ฉันเห็นว่าโปรแกรมเมอร์ไม่สนใจว่าคำจำกัดความความเสมอภาคที่ใช้คืออะไรเมื่อเขารู้ว่าเนื้อหาของตัวแปรถูก จำกัด ให้อยู่ในรูปแบบเฉพาะก่อนเวลา
godlygeek

@ godlygeek ที่น่าสนใจคำถามคือเกี่ยวกับการเปรียบเทียบความเท่าเทียมกันของตัวเลขราวกับว่าพวกเขาเป็นสตริงมันเหมาะกับกรณีของตัวแปรที่ จำกัด ก่อนเวลากับรูปแบบเฉพาะหรือไม่?
Emmanuel

ตัวอย่างของคุณ ( b=234) เหมาะกับรูปแบบนั้น - คุณรู้ว่าไม่ใช่ +234 หรือ "234" หรือ "233 + 1" เนื่องจากคุณกำหนดด้วยตัวเองดังนั้นคุณจึงรู้ว่ามันเปรียบเทียบเป็นสตริงและตัวเลขมีความถูกต้องเท่ากัน แต่สคริปต์ของ OP เนื่องจากใช้อินพุตเป็นอาร์กิวเมนต์บรรทัดคำสั่งจึงไม่มีข้อ จำกัด - ลองเรียกมันว่าเป็น./param.sh 0+1หรือ./param.sh " 1"
godlygeek
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.