if条件に基づくケースのフォールスルー


11

私はbashのケース条件内のif条件に基づいてフォールスルーが発生する方法を探しています。例えば:

input="foo"
VAR="1"

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

        # perform fallthrough

    else

        # do not perform fallthrough

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

上記のコードで、変数VAR1の場合、ケース条件にフォールスルーを実行させたいと思います。


1
小さな質問:if [ $VAR -eq 1 ]; thenコードの一部からそこにあるものにジャンプしようとしてい*)ますか?それはフォールスルーと呼ばれるものとは完全に異なるため、質問の言い回しを少し誤解させるだけです。
Sergiy Kolodyazhnyy

回答:


8

できません。caseフォールスルーを行う方法は、;;セパレータを;&(または;;&)に置き換えることです。そして、それをifの中に入れるのは構文エラーです。

ロジック全体を通常の条件として記述できます。

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

はい、できます!:)
NotAnUnixNazi

@Isaac、ええ、ええ、彼らはフォールスルーをに基づいて指定しましたがif
ilkkachu

+1明確にするために:私はあなたの回答に賛成票を投じました。:)。
NotAnUnixNazi

7

ロジックを再構築することをお勧めします。代わりに「フォールスルー」コードを関数に入れます。

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

出力

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

7

次のスクリプトは、$var最初にテストし、次にに応じてフォールスルー(;&a を使用case)を実行するという意味で、テストを「裏返し」にし$inputます。

これは、「フォールスルーを実行する」かどうかの問題は、実際には$inputifにのみ依存するため$varです1。それが他の価値であれば、フォールスルーを行うかどうかの質問は問う必要さえありません。

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

または、なしcase

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

あなたはOPが実際に望んでいたものを釘付けにしたと思います*)。既に+1しています。
セルギーKolodyazhnyy

5

私がすることではありませんが、次の方法で何かを達成することができます。

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

両方の変数を一度にテストます(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

テスト時:

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

クリーンでシンプル。

$newVARをブール値に変換するには、テスト対象の値()に2つの値のみが必要であるため、if句が存在することを理解してください。VARをブール値にすることができる場合は、で0(ではない1)をテストし、caseを削除しifます。


1

あなたはフォールスルーをデフォルトにすることができますが、条件が満たされた場合にのみコードが実行されるという条件を置きます

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

しかし、ilkkachuが示唆したように、スイッチではなく条件を使用することもできます。


1

誰かがあなたのコードを理解していないことについて不平を言ってもかまわない場合は、2つの条件の順序を入れ替えることができます。

input="foo"
VAR="1"

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

または:

input="foo"
VAR="1"

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

シンプルで明確(少なくとも私にとって)。caseフォールスルー自体はサポートしていません。しかし*)&&後で置き換えてesac、他のブランチの戻り値を尊重することができます。


-4

新規;&および;;&演算子は 4.0導入されましたBashが、どちらも同じような状況で役立つ場合がありますが、あなたの場合は役に立たないと思います。これはman bash、これらの演算子について言うものです:

もし;; 演算子を使用すると、最初のパターン一致の後に後続の一致は試行されません。;;の代わりに;&を使用する 次のパターンのセットに関連付けられたリストから実行を続行します。;;の代わりに;;&を使用する シェルに、ステートメント内の次のパターンリストがある場合はそれをテストさせ、一致した場合に関連リストを実行させます。

言い換えれば、;&我々はそれを知っているから通って、と秋であるC;;&なりますが、bash代わりに返すの残りのケースを確認し case、完全にブロック。;;&実際の動作の良い例を/programming//a/24544780/3691891で見つけることができます

そうは言っても、どちら;&;;&スクリプトに使用することも、使用することもできません。どちらのスクリプト*)も常に実行されるからです。

次のスクリプトは機能し、ロジックを再配置せずに必要なことを実行しますが、これは例としてのみ考え、決してそれに依存しないでください。非常に脆弱です。私はここからアイデアを取り入れまし

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

なぜダウン投票なのですか?
はArkadiusz Drabczyk

1
これはおもちゃの例ではうまくいくかもしれませんが、ほとんど理解できず、より大きなスクリプトではうまくいきません。gotoをシミュレートする方法は非常に壊れやすく、gotoを本当にシミュレートすると言っても過言です。コードはjumpto関数から戻り、その後に続くものをすべて実行します。これは、ジャンプ後のブロックft:と同じ複雑なコマンドの最後のコマンドである;;ため、これは間のブロックの後に実行を継続することと同じであり、偶然jumptoです。
Gilles 'SO-悪をやめる'

1
わかりました、私はそれを私の答えではっきりと強調しました。
Arkadiusz Drabczyk
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.