Chuyển trường hợp với sự sụp đổ?


193

Tôi đang tìm kiếm cú pháp chính xác của câu lệnh chuyển đổi với các trường hợp sai lầm trong Bash (lý tưởng không phân biệt chữ hoa chữ thường). Trong PHP tôi sẽ lập trình nó như sau:

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

Tôi muốn điều tương tự ở Bash:

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

Điều này bằng cách nào đó không hoạt động: chức năng do_what_you_are_supposed_to_do()nên được kích hoạt khi $ C là 2 HOẶC 3.


4
Đừng sử dụng chức năng gọi với parens !!! Vì bạn có thể định nghĩa một hàm trong bash bằng cách sử dụng function fname { echo "Inside fname"; return 0; }hoặc fname() { echo "inside fname"; return 0; }đặt parens vào lệnh gọi hàm có thể trông giống như đó là một khiếm khuyết hàm. Chức năng nên được gọi là giống như bất kỳ chương trình dòng lệnh khác như mv, cp, rsync, ls, cd, vv ... Trong trường hợp này chúng ta gọi là fname thích vậy: fname $ARGS.
Charles Addis

do_nothing()sẽ là một tuyên bố SKIP? Sử dụng :.
sjas

Câu trả lời:


309

Sử dụng một thanh dọc ( |) cho "hoặc".

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

30
Hoặc trong trường hợp đơn giản này, một lớp nhân vật[23])
SiegeX

4
@Mischka - Tôi lưu ý rằng bạn chưa chấp nhận câu trả lời này, có phải vì nó không trả lời phần câu hỏi không? Logic Fall Fall rất hữu ích khi xử lý đặc biệt nên xảy ra trước đó do_what_you_are_supposed_to_do(), thu gọn cả "2" và "3" vào một trường hợp không giải quyết được điều này. Tôi không chắc chắn nếu chỉnh sửa câu hỏi để làm cho rõ ràng hơn là hợp lý, vì rõ ràng là nhiều người đã tìm thấy câu trả lời này hữu ích.
Tyson

1
@Tyson OP không chấp nhận câu trả lời, vì đây là người dùng chưa đăng ký. Đối với logic "rơi qua", như các lập trình viên thường hiểu, cơ thể câu hỏi thể hiện sự sụp đổ của điều kiện, chứ không phải logic rơi. (Lưu ý việc sử dụng breaktrong mã php.) Chỉnh sửa các câu hỏi, hoặc tiêu đề của nó, vào ngày này sẽ làm mất hiệu lực rất nhiều các câu trả lời mà ta cung cấp mùa thu qua logic, và có lẽ không nên được thực hiện. Fall-through không có trong tiêu đề cho đến khi một số chỉnh sửa của người dùng khác, nhưng bây giờ đã quá muộn để đưa nó trở lại.
dùng7412956

100

Các bashphiên bản gần đây cho phép thông qua bằng cách sử dụng ;&thay cho ;;: chúng cũng cho phép tiếp tục kiểm tra trường hợp bằng cách sử dụng ;;&ở đó.

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

đầu ra mẫu

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

1
Logic này trong ví dụ này rất khó theo dõi. Ngoài ra, tôi không nghĩ ví dụ này thực sự chứng minh sự khác biệt giữa ;&;;&. Tôi đã thay đổi "24"thành ;;& # resumevà nhận được kết quả tương tự, vì vậy tôi vẫn tự hỏi khi nào bạn sẽ sử dụng dự phòng ;&.
wvducky

1
đó là một ví dụ đơn giản cho một điều phức tạp - tôi đã thay đổi ?4để [13]4làm cho nó rõ ràng hơn và để thay đổi của bạn thành một thay đổi đột phá
Jasen

26
  • Không sử dụng ()đằng sau tên hàm trong bash trừ khi bạn muốn xác định chúng.
  • sử dụng [23]trong trường hợp để phù hợp 2hoặc3
  • trường hợp chuỗi tĩnh nên được bao quanh bởi ''thay vì""

Nếu được đặt trong "", trình thông dịch (không cần thiết) cố gắng mở rộng các biến có thể có trong giá trị trước khi khớp.

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

Đối với trường hợp khớp không nhạy, bạn có thể sử dụng các lớp ký tự (như [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

Nhưng abrakhông trúng bất cứ lúc nào vì nó sẽ được khớp với trường hợp đầu tiên.

Nếu cần, bạn có thể bỏ qua ;;trong trường hợp đầu tiên để tiếp tục kiểm tra các kết quả khớp trong các trường hợp sau. ( ;;nhảy tới esac)


Bạn cũng có thể chuyển đổi chữ C thành chữ thường case "${C,,}" innếu trường hợp không quan trọng
Sprinterfreak

1
Điều gì xảy ra nếu bạn bỏ qua ;;? Bạn không nên sử dụng ;&cho dự phòng?
HelloGoodbye

1
Tôi nhận được một lỗi cú pháp nếu tôi bỏ qua ;; tôi cần sử dụng ;;&nếu tôi muốn tiếp tục thử nghiệm.
Jasen

do_wild_mysterious_thingslàm cho ngày của tôi
Julien__

14

Thử cái này:

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

1
đó là một mẹo rất hữu ích Ít nhất là đối với Bash 4.3.11. Tôi không bận tâm để thử nó trên bất kỳ người khác.
Daniel

3
Lưu ý: Điều này không hoạt động đối với bash 3.2, đây vẫn là bash mặc định trong macOS.
Daniel Kirchmeier

13

Nếu các giá trị là số nguyên thì bạn có thể sử dụng [2-3] hoặc bạn có thể sử dụng [5,7,8]cho các giá trị không liên tục.

#!/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

Nếu các giá trị là chuỗi thì bạn có thể sử dụng |.

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

là những gì shiftvào cuối cho?
Milkncookiez

1
shiftxóa đối số đầu tiên trên danh sách đối số CLI. Về cơ bản trên mỗi lần lặp của vòng lặp này luôn $1được sử dụng để nhận từng đối số từ danh sách đối số CLI với sự trợ giúp của shift.
rashok
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.