case + วิธีใช้งานเท่ากันหรือน้อยกว่าหรือน้อยกว่า


9

เป้าหมายของฉันคือการตรวจสอบช่วงของตัวเลขด้วย (เฉพาะกับcase+ esac) และพิมพ์ช่วง ตัวอย่างเช่น:

  • หากตัวเลขอยู่ระหว่าง 0 ถึง 80 ให้พิมพ์ >=0<=80
  • หากตัวเลขอยู่ระหว่าง 81 ถึง 100 ให้พิมพ์ >=81<=100
  • เป็นต้น

ปัญหาเกี่ยวกับสคริปต์ของฉันด้านล่างพิมพ์เฉพาะใน>=0<=90กรณีที่หมายเลขระหว่าง 0 ถึง 9 วิธีการแก้ไขสคริปต์ของฉันเพื่อที่จะพิมพ์ผลลัพธ์ที่ถูกต้องตามช่วงหมายเลข?

#!/bin/ksh
read number 
case $number in 
 [0-80])  echo ">=0<=80";; 
 [81-100]) echo ">=81<=100";; 
 [101-120]) echo ">=101<=120";;
 [121-300]) echo ">=121<=300";;
esac

คำตอบ:


6

caseเป็นเพียงสำหรับการจับคู่แบบมันจะไม่ทำการประเมินผลทางคณิตศาสตร์ (ยกเว้นบางทีถ้าคุณพิจารณาzshของ<x-y>ผู้ประกอบการจับคู่รูปแบบขยาย) [...]เป็นเพียงเพื่อให้ตรงกับหนึ่งในตัวละคร (หรือองค์ประกอบเรียงในการใช้งานบางส่วน) ตั้งอยู่บนพื้นฐานที่ระบุไว้ภายใน ตัวอย่างเช่น[0-80]จะจับคู่อักขระหนึ่งตัวหากเป็นหนึ่งใน0ถึง8หรือ0(นั่นคือหนึ่งใน 0, 1, 2, 3, 4, 5, 6, 7, 8)

คุณสามารถจับคู่ตัวเลขด้วยรูปแบบเช่น:

case $(($number)) in
  ([0-9]|[1-7][0-9]|80) echo ">=0<=80";;
  (8[1-9]|9[0-9]|100) echo ">=81<=100";;
  ... and so on
esac

แต่คุณสามารถเห็นได้อย่างง่ายดายว่าไม่ใช่เครื่องมือที่เหมาะสม

[...]ตรงกับหนึ่งในตัวละครกับรายการของตัวละครที่ระบุเพื่อให้[121-300]ตรงกับตัวอักษรใด ๆ ที่เป็นทั้งแบบ 1, 2, 1-3, 0 หรือ 0 ดังนั้นจึงเป็นเรื่องเดียวกับหรือ[0-3][0123]

ใช้:

if [ "$number" -ge 0 ] && [ "$number" -le 80 ]; then
  echo ">=0<=80"
elif [ "$number" -ge 81 ] &&  [ "$number" -le 100 ]; then
  echo ">=81<=100"
elif ... and so on
  ...
fi

วิธีใช้อีกวิธีหนึ่งcaseจะเป็นเช่น:

case $((
  (number >= 0 && number <= 80)   * 1 +
  (number > 80 && number <= 100)  * 2 +
  (number > 100 && number <= 120) * 3 +
  (number > 120 && number <= 300) * 4)) in
  (1) echo ">=0<=80";;
  (2) echo ">=81<=100";;
  (3) echo ">=101<=120";;
  (4) echo ">=121<=300";;
  (0) echo "None of the above";;
esac

หรือใช้ผู้ประกอบการที่สาม ( x ? y : z):

case $((
  number >= 0 && number <= 80   ? 1 :
  number > 80 && number <= 100  ? 2 :
  number > 100 && number <= 120 ? 3 :
  number > 120 && number <= 300 ? 4 : 0)) in...

หรือชอบ @mikeserv คิดนอกกล่องกลับcaseตรรกะและตรง1กับความคุ้มค่าของการเปรียบเทียบทางคณิตศาสตร์เหล่านั้น


1
+1 if [ n < 0 ] - elif [ n <= 80 ] - elif [ n <= 100 ] ... - elseพิจารณา พิมพ์น้อยลงมีข้อผิดพลาดน้อยลง
peterph

@peterph มันใช้เวลาในการรันนานกว่า
เคนคม

4

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

case  1:${number:--} in
(1:*[!0-9]*|1:0*[89]*)
  ! echo NAN
;;
($((number<81))*)
    echo "$number >=0<=80"
;;
($((number<101))*)
    echo "$number >=81<=100"
;;
($((number<121))*)
    echo "$number >=101<=120"
;;
($((number<301))*)
    echo "$number >=121<=300"
;;
esac

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


👍ฉันชอบวิธีที่คุณคิดนอก / รอบ ๆ กล่อง
Stéphane Chazelas

@ StéphaneChazelas - caseผมชอบ มีบางสิ่งที่ยอดเยี่ยมที่คุณสามารถทำได้กับ$((คณิตศาสตร์))และcaseโดยเฉพาะอย่างยิ่งการมอบหมายโดยรอบในรูปแบบที่ไม่เคยเกิดขึ้นจนกว่าพวกเขาจะต้องการและคุณยังสามารถสร้างต้นไม้แยกวิเคราะห์ที่ขยายการสอบถามซ้ำซ้อนหากคุณใส่รูปแบบด้วยaliasโซ่ มันเป็นวิธีที่เร็วที่สุดที่เราจะได้เปลือกเพื่อทำสิ่งต่าง ๆ เช่นการแปลตัวอักษรและการแลกเปลี่ยนตัวอักษรสำหรับค่าไบต์ มันค่อนข้างเร็ว - C-Locale ASCII + <> ฐานแปดกรณีที่เลวร้ายที่สุดคือการขยายรูปแบบ POSIX 7 รูปแบบ
mikeserv

1

มันไม่ได้ดีมาก แต่คุณสามารถใช้สิ่งนี้:

 #!/bin/ksh

read number  

case $number in
[0-9]|[1-7][0-9]|80) echo  echo ">=0<=80";;
8[1-9]|9[0-9]|100) echo ">=81<=100";;
10[1-9]|11[0-9]|120) echo ">=101<=120";;
12[1-9]|130) echo ">=121<=300";;
esac

คุณอาจต้องการ "canonify" หมายเลขที่มี $ (($ number)) เพื่อครอบคลุมตัวเลขเช่น "001" หรือ "0x99" ... ซึ่งอาจครอบคลุมสำหรับ "12" และ "12 + 12" ซึ่งอาจหรืออาจ ไม่พึงปรารถนา
Stéphane Chazelas
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.