การเปรียบเทียบจำนวนเต็ม: การแสดงออกทางคณิตศาสตร์หรือการแสดงออกตามเงื่อนไข


20

ใน Bash คุณสามารถเปรียบเทียบจำนวนเต็มสองจำนวนได้โดยใช้นิพจน์เงื่อนไข

arg1 OP arg2

OP เป็นหนึ่ง-eq, -ne, -lt, -le, หรือ-gt -geตัวดำเนินการเลขคณิตเหล่านี้จะคืนค่าจริงถ้าarg1เท่ากับ, ไม่เท่ากับ, น้อยกว่า, น้อยกว่าหรือเท่ากับ, มากกว่าหรือมากกว่าหรือเท่ากับarg2ตามลำดับ Arg1และarg2อาจเป็นจำนวนเต็มบวกหรือลบ

หรือการแสดงออกทางคณิตศาสตร์:

<= >= < > การเปรียบเทียบ

== != ความเสมอภาคและความไม่เท่าเทียม

ทำไมเรามีสองวิธีที่แตกต่างกันในการเปรียบเทียบจำนวนเต็มสองตัว? จะใช้เมื่อใด

ตัวอย่างเช่น[[ 3 -lt 2 ]]ใช้นิพจน์เงื่อนไขและ(( 3 < 2 ))ใช้นิพจน์ทางคณิตศาสตร์ ทั้งคู่คืนค่า 0 เมื่อการเปรียบเทียบเป็นจริง

เมื่อเปรียบเทียบจำนวนเต็มสองจำนวนทั้งสองวิธีสามารถใช้แทนกันได้หรือไม่ ถ้าใช่ทำไม Bash มีสองวิธีมากกว่าหนึ่ง?


1
= != < <= > >=เปรียบเทียบสตริง 1 -eq 01but 1 != 01and 8 -lt 42but8 > 42
dave_thompson_085

มันมีมากเกินไปในนิพจน์ทางคณิตศาสตร์
ทิม

1
คุณจะต้องค้นหาใน bash changelogs เพื่อดูว่าเมื่อใดที่มีการเพิ่มแต่ละฟีเจอร์ ฉันสงสัยว่านิพจน์ทางคณิตศาสตร์ถูกเพิ่มเข้ามาช้ากว่าคำสั่งทดสอบ
เกล็นแจ็คแมน

ฉันไม่ได้ถามเกี่ยวกับการเปรียบเทียบสตริง @muru
ทิม

คำตอบ:


28

ใช่เรามีสองวิธีในการเปรียบเทียบจำนวนเต็มสองวิธี

ดูเหมือนว่าข้อเท็จจริงเหล่านี้ไม่ได้รับการยอมรับอย่างกว้างขวางในฟอรัมนี้:

  1. ภายในสำนวน[ ]ผู้ประกอบการสำหรับการเปรียบเทียบทางคณิตศาสตร์มี-eq, -ne, -lt, -le, และ-gt-ge

    [[ ]]ขณะที่พวกเขายังอยู่ในคำสั่งการทดสอบและภายใน

    ใช่ภายในสำนวนนี้=, <ฯลฯ เป็นผู้ประกอบการสตริง

  2. ภายในสำนวน(( ))ผู้ประกอบการสำหรับการเปรียบเทียบทางคณิตศาสตร์มี==, !=, <, <=, และ>>=

    ไม่มีนี้ไม่ได้เป็น "การขยายตัวทางคณิตศาสตร์" (ซึ่งเริ่มต้นด้วย$) $(( ))เช่น มันถูกกำหนดให้เป็น "คำสั่งผสม" ในทุบตีมนุษย์

    ใช่มันเป็นไปตามกฎเดียวกัน (ภายใน) ของ "ส่วนขยายทางคณิตศาสตร์" แต่ไม่มีเอาต์พุตเพียงค่าออกเท่านั้น มันสามารถใช้แบบนี้:

if (( 2 > 1 )); then ...

ทำไมเราถึงมีสองวิธีที่แตกต่างกันในการเปรียบเทียบจำนวนเต็มสองตัว?

ฉันเดาว่าสิ่งหลัง(( ))ได้รับการพัฒนาขึ้นเป็นวิธีที่ง่ายกว่าในการทำการทดสอบทางคณิตศาสตร์ มันเกือบจะเหมือนกันกับ$(( ))แต่ไม่มีผลผลิต

ทำไมสอง เหมือนกันว่าทำไมเราถึงมีการทดสอบสองแบบprintf(ภายนอกและแบบบิลด์อิน) หรือสี่แบบ (ภายนอกtest, บิวtestด์[และ[[) นั่นคือวิธีที่กระสุนเติบโตขึ้นปรับปรุงพื้นที่ในหนึ่งปีปรับปรุงบางส่วนในปีหน้า

จะใช้เมื่อใด

นั่นเป็นคำถามที่ยากมากเพราะไม่มีความแตกต่างที่มีประสิทธิภาพ แน่นอนว่ามีความแตกต่างบางประการเกี่ยวกับวิธีการ[ ]ทำงานและการ(( ))ทำงานภายใน แต่: ไหนดีกว่าการเปรียบเทียบจำนวนเต็มสองตัว คนใดคนหนึ่ง!

เมื่อเปรียบเทียบจำนวนเต็มสองจำนวนทั้งสองวิธีสามารถใช้แทนกันได้หรือไม่

สำหรับตัวเลขสองตัวฉันจำเป็นต้องพูดว่าใช่
แต่สำหรับตัวแปรการขยายการดำเนินการทางคณิตศาสตร์อาจมีความแตกต่างที่สำคัญที่ควรสนับสนุนอย่างใดอย่างหนึ่ง ฉันไม่สามารถพูดได้ว่าทั้งสองมีค่าเท่ากัน สำหรับหนึ่ง(( ))สามารถดำเนินการทางคณิตศาสตร์หลายอย่างในลำดับ:

if (( a=1, b=2, c=a+b*b )); then echo "$c"; fi

ถ้าใช่ทำไม Bash มีสองวิธีมากกว่าหนึ่ง?

หากทั้งสองเป็นประโยชน์ทำไมล่ะ


1
=เป็นการมอบหมายและ==เป็นการเปรียบเทียบในการขยายเลขคณิต คำถามเสนอราคาอย่างถูกต้อง แต่คำตอบนั้นผิด
ceving

12

ในอดีตtestคำสั่งนั้นมีอยู่ก่อน (อย่างน้อยก็ไกลถึงUnix Seventh Editionในปี 1979) จะใช้ประกอบการ=และ!=เพื่อเปรียบเทียบสตริงและ-eq, -ne, -ltและอื่น ๆ เพื่อเปรียบเทียบตัวเลข ตัวอย่างเช่นtest 0 = 00เป็นเท็จ แต่test 0 -eq 00เป็นจริง ฉันไม่รู้ว่าทำไมเลือกไวยากรณ์นี้ แต่อาจต้องหลีกเลี่ยงการใช้<และ>ซึ่งเชลล์จะแยกวิเคราะห์เป็นตัวดำเนินการเปลี่ยนเส้นทาง testคำสั่งมีไวยากรณ์อีกไม่กี่ปีต่อมา: เทียบเท่ากับ[ … ]test …

[[ … ]]ไวยากรณ์เงื่อนไขภายในซึ่ง<และ>สามารถนำมาใช้เป็นผู้ประกอบการโดยไม่ต้องอ้างถูกเพิ่มในภายหลังใน ksh มันยังคงความเข้ากันได้ย้อนหลังด้วย[ … ]ดังนั้นจึงใช้ตัวดำเนินการเดียวกัน แต่เพิ่ม<และ>เปรียบเทียบสตริง (ตัวอย่างเช่น[[ 9 > 10 ]]แต่[[ 9 -lt 10 ]]) สำหรับข้อมูลเพิ่มเติมให้ดูที่การใช้วงเล็บเดี่ยวหรือคู่ - ทุบตี

นิพจน์ทางคณิตศาสตร์ก็มาช้ากว่าtestคำสั่งใน Korn shellในบางครั้งในปี 1980 พวกเขาติดตามไวยากรณ์ของภาษา C ซึ่งเป็นที่นิยมอย่างมากในแวดวง Unix ดังนั้นพวกเขาจึงใช้โอเปอเรเตอร์ของ C: ==เพื่อความเท่าเทียม<=สำหรับน้อยหรือเท่ากันเป็นต้น

Unix Seventh Edition ไม่มีนิพจน์ทางคณิตศาสตร์ แต่มีexprคำสั่งซึ่งใช้ไวยากรณ์ C-like สำหรับการดำเนินการจำนวนเต็มรวมถึงตัวดำเนินการเปรียบเทียบ ในสคริปต์เปลือกตัวละคร<และ>จะต้องมีการยกมาเพื่อปกป้องพวกเขาจากเปลือกเช่นเทียบเท่ากับif expr 1 \< 2; … if test 1 -lt 2; …การเพิ่มการแสดงออกทางคณิตศาสตร์ให้กับเชลล์ทำให้การใช้งานส่วนใหญ่exprล้าสมัยดังนั้นจึงไม่เป็นที่รู้จักในปัจจุบัน

ในสคริปต์ sh คุณมักจะใช้นิพจน์ทางคณิตศาสตร์เพื่อคำนวณค่าจำนวนเต็มและ[ … ]เปรียบเทียบจำนวนเต็ม

if [ "$((x + y))" -lt "$z" ]; then 

ในสคริปต์ ksh, bash หรือ zsh คุณสามารถ((…))ใช้ได้ทั้งคู่

if ((x + y < z)); then 

[[ … ]]รูปแบบจะเป็นประโยชน์ถ้าคุณต้องการที่จะใช้เงื่อนไขที่เกี่ยวข้องกับสิ่งอื่นที่ไม่ใช่จำนวนเต็ม


1

ตามหน้า man test, = และ! = จะใช้สำหรับการเปรียบเทียบสตริงในขณะที่นิพจน์ -eq, -gt, -lt, -ge, -le และ -ne เป็นการเปรียบเทียบจำนวนเต็ม ฉันทำตามอนุสัญญานี้เสมอเมื่อเขียนเชลล์สคริปและใช้งานได้เสมอ โปรดระวังว่าถ้าคุณมีตัวแปรในนิพจน์คุณอาจจำเป็นต้องอ้างอิงตัวแปรในบางวิธีเพื่อหลีกเลี่ยงการทำการเปรียบเทียบแบบ null

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


ในโพสต์ของฉัน= และ!=เป็นตัวดำเนินการทางคณิตศาสตร์ในขณะที่ manpage ของtestเพียงแสดงตัวดำเนินการนิพจน์เงื่อนไข
ทิม
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.