สลับเคสด้วยการตกหล่นหรือไม่


193

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

switch($c) {
    case 1:
        do_this();
        break;
     case 2:
     case 3:
        do_what_you_are_supposed_to_do();
        break;
     default:
        do_nothing(); 
}

ฉันต้องการเหมือนกันใน Bash:

case "$C" in
    "1")
        do_this()
        ;;
    "2")
    "3")
        do_what_you_are_supposed_to_do()
        ;;
    *)
        do_nothing();
        ;; 
esac

สิ่งนี้ไม่ทำงาน: ฟังก์ชั่นdo_what_you_are_supposed_to_do()ควรถูกไล่ออกเมื่อ $ C เป็น 2 หรือ 3


4
อย่าใช้ฟังก์ชั่นการโทรด้วย parens !!! เนื่องจากคุณสามารถกำหนดฟังก์ชั่นในการทุบตีโดยใช้ทั้งfunction fname { echo "Inside fname"; return 0; }หรือfname() { echo "inside fname"; return 0; }วาง parens ในการเรียกใช้ฟังก์ชั่นสามารถดูเหมือนว่ามันเป็นฟังก์ชั่นการขาดดุล ฟังก์ชั่นควรจะเรียกว่าเหมือนโปรแกรมบรรทัดคำสั่งอื่น ๆ เช่นmv, cp, rsync, ls, cdฯลฯ ... ในกรณีนี้เราเรียก fname fname $ARGSชอบโดย:
ชาร์ลส์แอดดิส

do_nothing()จะเป็นคำสั่งข้าม? :ใช้
sjas

คำตอบ:


309

ใช้แถบแนวตั้ง ( |) สำหรับ "หรือ"

case "$C" in
"1")
    do_this()
    ;;
"2" | "3")
    do_what_you_are_supposed_to_do()
    ;;
*)
    do_nothing()
    ;;
esac

30
หรือในกรณีที่เรียบง่ายคลาสตัวละคร[23])
SiegeX

4
@Mischka - ฉันทราบว่าคุณยังไม่ได้รับคำตอบนี้เป็นเพราะมันไม่ได้ตอบคำถามที่ผิดพลาดหรือไม่? ตรรกะการตกหล่นมีประโยชน์ในกรณีที่การประมวลผลพิเศษควรเกิดขึ้นก่อนหน้าการdo_what_you_are_supposed_to_do()ยุบทั้ง "2" และ "3" ลงในเคสเดียวล้มเหลวในการแก้ปัญหานี้ ฉันไม่แน่ใจว่าการแก้ไขคำถามเพื่อให้ชัดเจนนี้มีเหตุผลหรือไม่เนื่องจากเห็นได้ชัดว่าหลายคนพบคำตอบนี้มีประโยชน์
Tyson

1
@Tyson The OP ไม่ยอมรับคำตอบเนื่องจากเป็นผู้ใช้ที่ไม่ลงทะเบียน สำหรับตรรกะ "fall-through" ตามที่โปรแกรมเมอร์เข้าใจแล้วร่างกายของคำถามแสดงให้เห็นถึงการยุบของเงื่อนไขไม่ใช่ตรรกะที่ล้มลง (Notice การใช้breakในโค้ด PHP.) แก้ไขคำถามหรือชื่อของตนในวันที่นี้จะเป็นโมฆะหลายคำตอบที่ไม่ให้ตกผ่านตรรกะและอาจจะไม่ควรทำ การร่วงผ่านไม่ได้อยู่ในชื่อจนกว่าจะมีการแก้ไขโดยผู้ใช้คนอื่นหลายคน แต่มันสายเกินไปที่จะลบมันออกตอนนี้
user7412956

100

bashเวอร์ชันล่าสุดอนุญาตให้ใช้งานแบบหล่นผ่านโดยใช้;&แทน;;: พวกเขายังอนุญาตให้ทำการตรวจสอบเคสอีกครั้งโดยใช้ที่;;&นั่น

for n in 4 14 24 34
do
  echo -n "$n = "
  case "$n" in
   3? )
     echo -n thirty-
     ;;&   #resume (to find ?4 later )
   "24" )
     echo -n twenty-
     ;&   #fallthru
   "4" | [13]4)
     echo -n four 
     ;;&  # resume ( to find teen where needed )
   "14" )
     echo -n teen
  esac
  echo 
done

ตัวอย่างผลลัพธ์

4 = four
14 = fourteen
24 = twenty-four
34 = thirty-four

1
ตรรกะนี้ในตัวอย่างนี้เป็นการยากที่จะติดตาม นอกจากนี้ผมไม่คิดเช่นนี้จริงๆแสดงให้เห็นถึงความแตกต่างระหว่างและ;& ;;&ผมเปลี่ยน"24"ไป;;& # resumeและได้ผลเหมือนกันดังนั้นฉันยังคงสงสัยว่าเมื่อคุณจะใช้;&fallthrough
wisbucky

1
มันเป็นตัวอย่างง่ายๆสำหรับสิ่งที่ซับซ้อน - ฉันเปลี่ยน?4เป็น[13]4ทำให้ชัดเจนมากขึ้นและทำให้การเปลี่ยนแปลงของคุณเปลี่ยนไปอย่าง
สิ้นเชิง

26
  • อย่าใช้()ชื่อฟังก์ชันในทุบตีเว้นแต่คุณต้องการกำหนด
  • ใช้[23]ในกรณีที่จะจับคู่2หรือ3
  • กรณีสตริงคงที่ควรจะล้อมรอบด้วย''แทน""

หากอยู่""ภายในล่าม (ไม่จำเป็น) จะพยายามขยายตัวแปรที่เป็นไปได้ในค่าก่อนการจับคู่

case "$C" in
'1')
    do_this
    ;;
[23])
    do_what_you_are_supposed_to_do
    ;;
*)
    do_nothing
    ;;
esac

สำหรับการจับคู่แบบตัวพิมพ์เล็กและตัวพิมพ์ใหญ่คุณสามารถใช้คลาสอักขระ (เช่น[23]):

case "$C" in

# will match C='Abra' and C='abra'
[Aa]'bra')
    do_mysterious_things
    ;;

# will match all letter cases at any char like `abra`, `ABRA` or `AbRa`
[Aa][Bb][Rr][Aa])
    do_wild_mysterious_things
    ;;

esac

แต่abraไม่ได้ตีทุกเวลาเพราะมันจะถูกจับคู่โดยกรณีแรก

หากจำเป็นคุณสามารถละเว้น;;ในกรณีแรกเพื่อดำเนินการทดสอบการจับคู่ในกรณีต่อไปนี้เช่นกัน ( ;;ข้ามไปที่esac)


นอกจากนี้คุณยังสามารถแปลง C เป็นตัวพิมพ์เล็กได้case "${C,,}" inหากกรณีไม่สำคัญ
Sprinterfreak

1
จะเกิดอะไรขึ้นถ้าคุณทำละเว้น;;? คุณไม่ควรใช้;&สำหรับการตกหล่นหรือ?
HelloGoodbye

1
ฉันได้รับข้อผิดพลาดทางไวยากรณ์หากฉันไม่ได้;; ใช้งาน;;&หากฉันต้องการทำการทดสอบต่อไป
Jasen

do_wild_mysterious_thingsทำวันของฉัน
Julien__

14

ลองสิ่งนี้:

case $VAR in
normal)
    echo "This doesn't do fallthrough"
    ;;
special)
    echo -n "This does "
    ;&
fallthrough)
    echo "fall-through"
    ;;
esac

1
นั่นเป็นเคล็ดลับที่มีประโยชน์มาก อย่างน้อยสำหรับ Bash 4.3.11 ฉันไม่ได้ใส่ใจที่จะลองกับคนอื่น ๆ
Daniel

3
หมายเหตุ: วิธีนี้ใช้ไม่ได้กับ bash 3.2 ซึ่งยังคงเป็น bash เริ่มต้นใน macOS
Danny Kirchmeier

13

หากค่าเป็นจำนวนเต็มคุณสามารถใช้[2-3]หรือคุณสามารถใช้[5,7,8]สำหรับค่าที่ไม่ต่อเนื่อง

#!/bin/bash
while [ $# -gt 0 ];
do
    case $1 in
    1)
        echo "one"
        ;;
    [2-3])
        echo "two or three"
        ;;
    [4-6])
        echo "four to six"
        ;;
    [7,9])
        echo "seven or nine"
        ;;
    *)
        echo "others"
        ;;
    esac
    shift
done

|ถ้าค่าเป็นสตริงแล้วคุณสามารถใช้

#!/bin/bash
while [ $# -gt 0 ];
do
    case $1 in
    "one")
        echo "one"
        ;;
    "two" | "three")
        echo "two or three"
        ;;
    *)
        echo "others"
        ;;
    esac
    shift
done

อะไรคือshiftจุดจบของชีวิต?
Milkncookiez

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