基于if条件的案例失败


11

我正在寻找一种方法来根据bash中的case条件中的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

Answers:


8

你不能 case失败的方法是;;;&(或;;&)替换分隔符。并将其放在if中是语法错误。

您可以将整个逻辑写为常规条件:

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

是的,他可以!:)
艾萨克

@Isaac,好吧,是的,尽管他们确实指定了将失败作为依据if
ilkkachu

+1要明确:我对您的答案投了赞成票。:)。
以撒

7

我建议重组您的逻辑:将“ fallthrough”代码放入函数中:

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首先进行测试,然后根据进行插入(;&在中使用case$input

我们这样做是因为是否“执行失败”实际上仅取决于$inputif $varis 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的实际需求,这似乎已从其原始的if语句跳转到了其中的任何内容*)。已经有我的+1。
Sergiy 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!

干净简单。

了解测试值($new)必须只有两个可能的值,这就是为什么存在if子句才能将VAR转换为布尔值的原因。如果可以将VAR设为布尔值,请在中测试0(不是1case并删除if


1

您可以将fallthrough设置为默认值,但要设置一个条件,使代码仅在满足条件时才执行

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

如果您不介意有人抱怨他们不了解您的代码,则只需切换两个条件的顺序即可:

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不支持失败本身。但是您可以*)使用&&after 替换esac为使其尊重其他分支的返回值。


-4

4.0引入了 new ;&;;&operator ,尽管它们在类似情况下都可能有用,但我认为它们在您的情况下没有用。这是说,这些运营商:Bashman bash

如果;; 使用运算符时,在第一个模式匹配之后将不尝试后续匹配。用;&代替;; 使执行继续与下一组模式相关联的列表。用;;&代替;; 使外壳测试语句中的下一个模式列表(如果有),并在成功匹配后执行任何关联的列表。

换句话说,;&就是通过一个秋天,因为我们知道从它C;;&品牌bash检查剩余的情况下,而不是从返回 case块完全。您可以;;&在这里找到一个很好的实际例子:https : //stackoverflow.com/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 '18

1
这可能在玩具示例中有效,但几乎难以理解,在较大的脚本中无效。模拟goto的方式非常脆弱,并且说它确实模拟goto是一种夸张。代码从jumpto函数返回并执行其后的所有内容。这等效于在块之间的继续执行,ft:并且这;;是一个巧合,因为这jumpto是与跳转到的块相同的复杂命令中的最后一条命令。
吉尔斯(Gilles)'“ SO-不要邪恶”

1
好吧,我在回答中明确强调了这一点。
Arkadiusz Drabczyk
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.