Ganti kasus dengan fallthrough?

193

Saya mencari sintaks yang benar dari pernyataan switch dengan kasus fallthrough di Bash (idealnya case-insensitive). Dalam PHP saya akan memprogramnya seperti:

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

Saya menginginkan hal yang sama di Bash:

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

Ini entah bagaimana tidak berfungsi: fungsi do_what_you_are_supposed_to_do()harus diaktifkan ketika $ C adalah 2 ATAU 3.

Mischka
sumber
4
Jangan gunakan fungsi panggilan dengan parens !!! Karena Anda dapat mendefinisikan fungsi dalam bash menggunakan salah satu function fname { echo "Inside fname"; return 0; }atau fname() { echo "inside fname"; return 0; }menempatkan parens pada panggilan fungsi dapat terlihat seperti definisi fungsi. Fungsi harus disebut seperti program baris perintah lain seperti mv, cp, rsync,ls , cd, dll ... Dalam hal ini kita sebut fname suka begitu: fname $ARGS.
Charles Addis
do_nothing()haruskah pernyataan SKIP? Gunakan :.
sjas

Jawaban:

309

Gunakan bilah vertikal ( |) untuk "atau".

case "$C" in
"1")
    do_this()
    ;;
"2" | "3")
    do_what_you_are_supposed_to_do()
    ;;
*)
    do_nothing()
    ;;
esac
geekosaurus
sumber
30
Atau dalam kasus sederhana ini kelas karakter[23])
SiegeX
4
@Mischka - Saya perhatikan Anda belum menerima jawaban ini, apakah karena itu tidak menjawab bagian fallthrough dari pertanyaan? Logika Fallthrough berguna di mana pemrosesan khusus harus terjadi sebelumnya do_what_you_are_supposed_to_do(), runtuh baik "2" dan "3" menjadi satu kasus gagal untuk mengatasi ini. Saya tidak yakin apakah mengedit pertanyaan agar lebih jelas ini masuk akal, karena sudah jelas bahwa banyak orang menganggap jawaban ini bermanfaat.
Tyson
1
@Tyson OP belum menerima jawaban, karena ini adalah pengguna yang tidak terdaftar. Mengenai logika "fall-through", seperti yang biasanya dipahami oleh programmer, badan pertanyaan menunjukkan kondisi yang runtuh, bukan logika fall-through. (Perhatikan penggunaan breakdalam kode php.) Mengedit pertanyaan, atau judulnya, pada tanggal ini akan membatalkan banyak jawaban yang tidak memberikan jatuh-melalui logika, dan mungkin tidak harus dilakukan. Fall-through tidak dalam judul sampai beberapa suntingan oleh pengguna lain, tetapi sudah terlambat untuk mengambilnya kembali sekarang.
user7412956
100

bashVersi terbaru memungkinkan fall-through dengan menggunakan ;&sebagai pengganti ;;: mereka juga memungkinkan melanjutkan pemeriksaan kasus dengan menggunakan di ;;&sana.

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

output sampel

4 = four
14 = fourteen
24 = twenty-four
34 = thirty-four
Jasen
sumber
1
Logika dalam contoh ini sulit diikuti. Juga, saya tidak berpikir contoh ini benar-benar menunjukkan perbedaan antara ;&dan ;;&. Saya mengubah "24"ke ;;& # resumedan mendapatkan hasil yang sama, jadi saya masih bertanya-tanya kapan Anda akan menggunakan ;&fallthrough.
wisbucky
1
itu adalah contoh sederhana untuk hal yang kompleks - aku berubah ?4untuk [13]4membuatnya lebih jelas, dan untuk membuat perubahan Anda perubahan melanggar
Jasen
26
  • Jangan gunakan di ()belakang nama fungsi di bash kecuali Anda ingin mendefinisikannya.
  • digunakan [23]untuk mencocokkan 2atau3
  • kasing statis harus ditutup dengan ''alih-alih""

Jika terlampir "", penerjemah (tidak perlu) mencoba untuk memperluas variabel yang mungkin dalam nilai sebelum pencocokan.

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

Untuk pencocokan yang tidak sensitif dengan huruf besar-kecil, Anda dapat menggunakan kelas karakter (seperti [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

Tetapi abratidak mengenai kapan saja karena akan dicocokkan dengan kasus pertama.

Jika perlu, Anda dapat menghilangkan ;;dalam kasus pertama untuk melanjutkan pengujian untuk pertandingan dalam kasus-kasus berikut juga. ( ;;melompat ke esac)

Sprinterfreak
sumber
Anda juga dapat mengonversi C ke huruf kecil case "${C,,}" injika kasing tidak penting
Sprinterfreak
1
Apa yang terjadi jika Anda menghilangkannya ;;? Bukankah seharusnya kau gunakan ;&untuk fallthrough?
HelloGoodbye
1
Saya mendapatkan kesalahan sintaks jika saya menghilangkan ;; saya harus menggunakan ;;&jika saya ingin melanjutkan pengujian.
Jasen
do_wild_mysterious_thingsmenjadikan hari saya
Julien__
14

Coba ini:

case $VAR in
normal)
    echo "This doesn't do fallthrough"
    ;;
special)
    echo -n "This does "
    ;&
fallthrough)
    echo "fall-through"
    ;;
esac
René Steetskamp
sumber
1
itu tip yang sangat membantu. Setidaknya untuk Bash 4.3.11. Saya belum repot untuk mencobanya pada orang lain.
Daniel
3
Catatan: Ini tidak berfungsi untuk bash 3.2, yang masih merupakan bash default di macOS.
Danny Kirchmeier
13

Jika nilainya bilangan bulat maka Anda dapat menggunakan [2-3]atau Anda dapat menggunakan [5,7,8]untuk nilai yang tidak berkelanjutan.

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

Jika nilainya adalah string maka Anda dapat menggunakan |.

#!/bin/bash
while [ $# -gt 0 ];
do
    case $1 in
    "one")
        echo "one"
        ;;
    "two" | "three")
        echo "two or three"
        ;;
    *)
        echo "others"
        ;;
    esac
    shift
done
rashok
sumber
untuk apa shiftpada akhirnya?
Milkncookiez
1
shiftmenghapus argumen pertama pada daftar argumen CLI. Pada dasarnya setiap iterasi dari loop ini selalu $1digunakan untuk mendapatkan setiap argumen dari daftar argumen CLI dengan bantuan shift.
rashok