Koşullara bağlı olarak vaka dönüşümü


11

Ben bash bir durum koşulunda bir if koşul dayalı düşme olması için bir yol arıyorum. Örneğin:

input="foo"
VAR="1"

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

        # perform fallthrough

    else

        # do not perform fallthrough

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

Yukarıdaki kodda, eğer değişken VARise 1, durum koşulunun geçişi gerçekleştirmesini istiyorum.


1
Küçük soru: if [ $VAR -eq 1 ]; thenKodun bir kısmından içinde ne varsa atlamaya mı çalışıyorsunuz *)? Çünkü bu, tam olarak adlandırılandan tamamen farklıdır, bu nedenle sorunuzun ifadesini biraz yanıltıcı hale getirir.
Sergiy Kolodyazhnyy

Yanıtlar:


8

Yapamazsın. Düşüşün yolu ayırıcıyı (veya ) ile casedeğiştirmektir . Ve bunu bir if içine koymak sözdizimi hatasıdır.;;;&;;&

Tüm mantığı normal bir koşullu olarak yazabilirsiniz:

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

Evet, yapabilir ! :)
Isaac

@Isaac, peki, evet, onlar a if.
ilkkachu

+1 Açık olmak gerekirse: Cevabınızı oy kullandım. :).
Isaac

7

Mantığınızı yeniden yapılandırmanızı öneririm: "fallthrough" kodunu bir işleve koy:

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

çıktılar

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

7

Aşağıdaki komut dosyası, testimizi $varönce test ettiğimiz ve daha sonra bağlı olarak ( ;&a case) kullanarak geçişi gerçekleştirdiğimiz anlamıyla " ters yüz" haline getirir $input.

Olsun veya olmasın sorusu "fallthrough gerçekleştirmek" için bu yapılmaktadır üzerinde gerçekten sadece bağlıdır $inputeğer $varolduğunu 1. Başka bir değer varsa, geçişin yapılıp yapılmayacağı sorusunun sorulması bile gerekmez.

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

Veya case:

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

Bence OP'nin aslında ne istediğini çiviledin, ki bu orijinal if deyiminden ne içeriğe atlıyor gibi görünüyor *). Zaten + 1'im var.
Sergiy Kolodyazhnyy

5

Yapacağım bir şey değil, ama yaklaşan bir şey elde edebilirsiniz:

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

Her iki değişkeni bir kerede test edin (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

Test hakkında:

$ ./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!

Temiz ve basit.

VAR'ı $newbir Boolean değerine dönüştürmek için , test edilen değer ( ) yalnızca iki olası değere sahip olmalıdır. VAR, bir Boole olarak oluşturulabilirse, 'de 0(değil 1) için test edin caseve kaldırın if.


1

Geçişi varsayılan olarak yapabilirsiniz, ancak kodun yalnızca koşul yerine getirildiğinde çalıştırıldığı bir koşul yerleştirebilirsiniz

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

Ancak ilkkachu'nun önerdiği gibi, geçiş yapmak yerine koşulları da kullanabilirsiniz.


1

Birinin kodunuzu anlamadığından şikayetçi olursanız, iki koşulun sırasını değiştirebilirsiniz:

input="foo"
VAR="1"

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

Veya:

input="foo"
VAR="1"

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

Basit ve net (en azından benim için). casedüşmeyi desteklemez. Ancak diğer dalların dönüş değerlerine saygı göstermek için after *)ile değiştirebilirsiniz .&&esac


-4

Yeni ;&ve ;;&operatörler 4.0'da tanıtıldıBash ve her ikisi de benzer durumlarda yararlı olsa da, sizin durumunuzda hiçbir faydası olmadığını düşünüyorum. Bu man bashoperatörler hakkında söylenenler:

Eğer ;; operatörü kullanıldığında, ilk patern eşleşmesinden sonra hiçbir eşleşme denenmez. Kullanımı; & yerine ;; yürütmenin bir sonraki kalıp kümesiyle ilişkili listeyle devam etmesine neden olur. ;; yerine; kabuğun deyimdeki bir sonraki kalıp listesini test etmesine ve varsa başarılı bir eşleşmede ilişkili listeyi yürütmesine neden olur.

Başka bir deyişle, ;&üzerinden bir düşüş olduğunu ve gelen bildiğimiz Cve ;;&markaları bashdavaları kalan yerine dönen kontrol casetamamen bloğun. ;;&Eylem için güzel bir örnek burada bulabilirsiniz: https://stackoverflow.com/a/24544780/3691891 .

Bununla birlikte, senaryonuzda ;&ne ;;&kullanılabilir ne de kullanılamaz çünkü ikisi de gidecekti, *)her zaman çalıştırılacaktı.

Aşağıdaki komut dosyası mantığı yeniden düzenlemeden çalışır ve istediğinizi yapar, ancak yalnızca örnek olarak düşünün ve asla ona güvenmeyin, çok kırılgandır. Fikri buradan aldım :

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

Neden inişli çıkışlı?
Arkadiusz Drabczyk

1
Bu bir oyuncak örneğinde işe yarayabilir, ancak neredeyse anlaşılmaz ve daha büyük bir senaryoda çalışmaz. Gitmeyi simüle etme yönteminiz son derece kırılgandır ve gotoyu gerçekten simüle ettiğini söylemek abartıdır. Kod jumptoişlevden döner ve bundan sonra gelenleri yürütür. Bunun, bloktan sonra devam eden yürütmeye eşdeğer olması ft:ve ;;bir tesadüf olması jumpto, çünkü jumped-to bloğu ile aynı karmaşık komuttaki son komuttur.
Gilles 'SO- kötü olmayı kes'

1
Tamam, cevabımda bunu açıkça vurguladım.
Arkadiusz Drabczyk
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.