Kasus jatuh berdasarkan kondisi jika


11

Saya mencari cara agar fallthrough terjadi berdasarkan kondisi if dalam kondisi case di bash. Sebagai contoh:

input="foo"
VAR="1"

case $input in
foo)
    if [ $VAR = "1" ]; then

        # perform fallthrough

    else

        # do not perform fallthrough

    fi
;;
*)
    echo "fallthrough worked!"
;;
esac

Dalam kode di atas, jika variabelnya VARadalah 1, saya ingin kondisi case melakukan fallthrough.


1
Pertanyaan kecil: Apakah Anda mencoba untuk beralih dari if [ $VAR -eq 1 ]; thenbagian kode ke apa pun yang ada di dalamnya *)? Karena itu sama sekali berbeda dari apa yang disebut fallthrough, sehingga membuat kalimat pertanyaan Anda hanya sedikit menyesatkan.
Sergiy Kolodyazhnyy

Jawaban:


8

Kamu tidak bisa Cara untuk casejatuh adalah mengganti ;;pemisah dengan ;&(atau ;;&). Dan itu adalah kesalahan sintaksis untuk memasukkannya ke dalam if.

Anda dapat menulis seluruh logika sebagai persyaratan reguler:

if [ "$input" != "foo" ] || [ "$VAR" = 1 ]; then
    one branch ...
else   # $input = "foo" && $VAR != 1
    another branch...
fi


@ Isaac, well, yeah, meskipun mereka menentukan berdasarkan kesalahan pada if.
ilkkachu

+1 Agar lebih jelas: Saya memilih jawaban Anda. :)
NotAnUnixNazi

7

Saya sarankan merestrukturisasi logika Anda: alih-alih masukkan kode "fallthrough" ke dalam fungsi:

fallthrough() { echo 'fallthrough worked!'; }

for input in foo bar; do
    for var in 1 2; do
        echo "$input $var"
        case $input in
            foo)
                if (( var == 1 )); then
                    echo "falling through"
                    fallthrough
                else
                    echo "not falling through"
                fi
            ;;
            *) fallthrough;;
        esac
    done
done

output

foo 1
falling through
fallthrough worked!
foo 2
not falling through
bar 1
fallthrough worked!
bar 2
fallthrough worked!

7

Script berikut mengubah tes Anda "dalam ke luar" dalam arti bahwa kami menguji $varterlebih dahulu dan kemudian melakukan fallthrough (menggunakan ;&dalam a case) tergantung pada $input.

Kami melakukan ini karena pertanyaan apakah atau tidak untuk "melakukan fallthrough yang" benar-benar hanya tergantung pada $inputjika $varadalah 1. Jika ada nilai lain, pertanyaan apakah akan melakukan fallthrough bahkan tidak harus ditanyakan.

#/bin/bash

input='foo'
var='1'

case $var in
    1)
        case $input in
            foo)
                echo 'perform fallthrough'
                ;&
            *)
                echo 'fallthough worked'
        esac
        ;;
    *)
        echo 'what fallthrough?'
esac

Atau, tanpa case:

if [ "$var" -eq 1 ]; then
    if [ "$input" = 'foo' ]; then
        echo 'perform fallthrough'
    fi
    echo 'fallthough worked'
else
    echo 'what fallthrough?'
fi

Saya pikir Anda memaku apa yang sebenarnya diinginkan OP, yang tampaknya akan melompat dari pernyataan aslinya jika ke apa pun di dalamnya *). Sudah memiliki +1 saya.
Sergiy Kolodyazhnyy

5

Bukan sesuatu yang akan saya lakukan, tetapi Anda dapat mencapai sesuatu yang mendekati dengan:

shopt -s extglob # for !(*)
default='*'
case $input in
  (foo)
    if [ "$VAR" = 1 ]; then
      echo going for fallthrough
    else
      echo disabling fallthrough
      default='!(*)'
    fi ;;&

  ($default)
    echo fallthrough
esac

2

Uji kedua variabel sekaligus (bash 4.0-alpha +):

#!/bin/bash
while (($#>1)); do
    input=$1    VAR=$2
    echo "input=${input} VAR=${VAR}"; shift 2

    if [ "$VAR" = 1 ]; then new=1; else new=0; fi

    case $input$new in
    foo0)   echo "do not perform fallthrough"   ;;
    foo*)   echo "perform fallthrough"          ;&
    *)      echo "fallthrough worked!"          ;;
    esac

    echo
done

Pada pengujian:

$ ./script foo 0   foo 1   bar baz
input=foo VAR=0
do not perform fallthrough

input=foo VAR=1
perform fallthrough
fallthrough worked!

input=bar VAR=baz
fallthrough worked!

Bersih dan sederhana.

Memahami bahwa nilai yang diuji ( $new) harus hanya memiliki dua nilai yang mungkin, itulah mengapa klausa if ada di sana, untuk mengubah VAR menjadi nilai Boolean. Jika VAR dapat dibuat menjadi Boolean, maka uji untuk 0(tidak 1) di casedan menghapus if.


1

Anda dapat menjadikan fallthrough sebagai default tetapi menempatkan suatu kondisi yang hanya dijalankan oleh kode jika kondisi terpenuhi

#!/bin/bash

input='foo'
var='1'

case $input in
foo)
        echo "Do fall through"
;& #always fall through
*)
        if [ $var = "1" ] #execute only if condition matches
        then
        echo "fallthrough took place"
        fi
esac

Tetapi seperti yang disarankan ilkkachu Anda juga dapat menggunakan kondisi daripada beralih.


1

Jika Anda tidak keberatan seseorang mengeluh tentang mereka yang tidak memahami kode Anda, Anda dapat dengan mudah mengubah urutan kedua persyaratan:

input="foo"
VAR="1"

if 
    case $input in
    foo)
        [ $VAR = "1" ]
    ;;
    esac
then
    echo "fallthrough worked!"
fi

Atau:

input="foo"
VAR="1"

case $input in
foo)
    [ $VAR = "1" ]
;;
esac &&
    echo "fallthrough worked!"

Sederhana dan jelas (setidaknya bagi saya). casetidak mendukung fallthrough itu sendiri. Tetapi Anda dapat mengganti *)dengan &&after esacuntuk menghormati nilai pengembalian cabang lain.


-4

Baru ;&dan ;;&operator yang diperkenalkan di Bash 4.0 dan meskipun mereka berdua mungkin berguna dalam situasi yang sama saya pikir mereka tidak berguna dalam kasus Anda. Inilah yang man bashdikatakan tentang operator ini:

Jika;; operator digunakan, tidak ada kecocokan berikutnya yang dicoba setelah pencocokan pola pertama. Menggunakan; & sebagai pengganti ;; menyebabkan eksekusi untuk melanjutkan daftar yang terkait dengan set pola berikutnya. Menggunakan ;; & sebagai pengganti ;; menyebabkan shell untuk menguji daftar pola selanjutnya dalam pernyataan, jika ada, dan menjalankan daftar terkait pada pertandingan yang berhasil.

Dengan kata lain, ;&adalah jatuh dan seperti yang kita tahu dari Cdan ;;&membuat bashmemeriksa sisa kasus alih-alih kembali dari caseblok sepenuhnya. Anda dapat menemukan contoh ;;&aksi yang bagus di sini: /programming//a/24544780/3691891 .

Yang sedang berkata, tidak satu pun ;&tidak ;;&dapat digunakan dalam naskah Anda karena keduanya akan pergi ke *)yang akan selalu berjalan.

Script berikut ini berfungsi dan melakukan apa yang Anda inginkan tanpa mengatur ulang logika tetapi menganggapnya hanya sebagai contoh dan tidak pernah bergantung padanya, itu terlalu rapuh. Saya telah mengambil ide dari sini :

#!/usr/bin/env bash

function jumpto
{
    label=$1
    cmd=$(sed -n "/$label:/{:a;n;p;ba};" "$0" | grep -v ':$')
    cmd=$(echo "$cmd" | sed 's,;;,,')
    cmd=$(echo "$cmd" | sed 's,esac,,')
    eval "$cmd"
}

input="foo"
VAR="1"

case $input in
foo)
    if [ $VAR = "1" ]; then

        printf "perform fallthrough\n"
        jumpto ft
    else
        printf "do not perform fallthrough\n"

    fi
;;
*)
    ft:
    echo "fallthrough worked!"
;;
esac

Mengapa downvote?
Arkadiusz Drabczyk

1
Ini mungkin bekerja dalam contoh mainan tetapi hampir tidak bisa dipahami dan tidak akan berhasil dalam skrip yang lebih besar. Cara Anda mensimulasikan goto sangat rapuh, dan mengatakan bahwa itu benar-benar mensimulasikan goto adalah berlebihan. Kode kembali dari jumptofungsi dan menjalankan apa pun yang datang setelahnya. Fakta bahwa ini setara dengan melanjutkan eksekusi setelah blok antara ft:dan ;;merupakan kebetulan karena jumptomerupakan perintah terakhir dalam perintah kompleks yang sama dengan blok lompat-ke.
Gilles 'SANGAT berhenti menjadi jahat'

1
OK, saya jelas menekankan itu dalam jawaban saya.
Arkadiusz Drabczyk
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.