【问题标题】:Switch case with fallthrough?有故障的开关盒?
【发布时间】:2011-07-30 13:18:18
【问题描述】:

我正在寻找 switch 语句的正确语法,在 Bash 中具有失败的情况(理想情况下不区分大小写)。 在 PHP 中我会这样编程:

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

我希望在 Bash 中也一样:

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

这在某种程度上不起作用:函数 do_what_you_are_supposed_to_do() 应该在 $C 为 2 OR 3 时触发。

【问题讨论】:

  • 不要使用带括号的调用函数!!!由于您可以使用function fname { echo "Inside fname"; return 0; }fname() { echo "inside fname"; return 0; } 在bash 中定义函数,因此在函数调用上放置括号看起来就像是函数定义。函数应该像任何其他命令行程序一样被调用,例如 mvcprsynclscd 等......在这种情况下,我们像这样调用 fname:fname $ARGS
  • do_nothing() 应该是 SKIP 语句吗?使用:

标签: bash switch-statement


【解决方案1】:

使用竖线 (|) 表示“或”。

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

【讨论】:

  • 或者在这个简单的例子中是一个字符类[23])
  • @Mischka - 我注意到你没有接受这个答案,是因为它没有回答问题的失败部分吗?在do_what_you_are_supposed_to_do() 之前应该进行特殊处理的情况下,故障处理逻辑很有用,将“2”和“3”合并为一个案例无法解决这个问题。我不确定编辑问题以使其更清晰是否合理,因为很明显很多人都认为这个答案很有帮助。
  • @Tyson OP 没有接受答案,因为它是未注册用户。至于“失败”逻辑,正如程序员通常理解的那样,问题主体展示了条件崩溃,不是失败逻辑。 (注意在 php 代码中使用 break。)此时编辑问题或其标题将使许多 确实 提供失败逻辑的答案无效,并且可能不应该完成不了。直到其他用户进行了几次编辑后,标题中才出现失败,但现在将其收回为时已晚。
【解决方案2】:
  • 请勿在 bash 中的函数名称后面使用 (),除非您喜欢定义它们。
  • 使用[23] 匹配23
  • 静态字符串大小写应该用''而不是""括起来

如果包含在"" 中,解释器(不必要地)在匹配之前尝试扩展值中可能的变量。

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

对于不区分大小写的匹配,可以使用字符类(如[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

但是abra 没有任何时候命中,因为它将被第一个案例匹配。

如果需要,您也可以在第一种情况下省略 ;;,以便在以下情况下继续测试匹配项。 (;; 跳转到esac

【讨论】:

  • 如果大小写不重要,您也可以将 C 转换为小写 case "${C,,}" in
  • 如果你省略了;;,会发生什么?你不应该使用;& 进行失败吗?
  • 如果我省略;;,我会收到语法错误如果我想继续测试,我需要使用;;&
【解决方案3】:

最近的bash 版本允许通过使用;& 而不是;; 进行直通: 他们还允许在那里使用;;& 恢复案例检查。

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

样本输出

4 = four
14 = fourteen
24 = twenty-four
34 = thirty-four

【讨论】:

  • 这个例子中的逻辑很难理解。另外,我不认为这个例子真正展示了;&;;& 之间的区别。我将"24" 更改为;;& # resume 并得到了相同的结果,所以我仍然想知道您何时会使用;& fallthrough。
  • 这是一个复杂事物的简单示例 - 我将 ?4 更改为 [13]4 以使其更明显,并使您的更改成为重大更改
  • 不幸的是,macos 的 bash 不支持 :(
  • @JerryGreen 我能说什么,这是我的输出:test.sh: line 7: syntax error near unexpected token `&' test.sh: line 7: ` ;;& #resume (to find ?4 later )' 这是我的bash --version:GNU bash,版本 3.2.57(1)-release (x86_64-apple-darwin19)跨度>
  • @v01pe 哦,对不起。我每天在 macos 和 windows 之间切换 10 次(使用类似 linux 的 MINGW64 shell),实际上我什至没有意识到我在 windows LOL 上使用了这个脚本。刚刚在我的 macbook 上使用相同的(预装)bash 版本进行了尝试:我确认,它不起作用:\ 在 windows 上虽然它显示GNU bash, version 4.4.23(1)-release (x86_64-pc-msys),所以它似乎是较新 Bash 版本的一个功能:\ Thx for the注意顺便说一句! (由于信息错误,我删除了我之前的评论)
【解决方案4】:

试试这个:

case $VAR in
normal)
    echo "This doesn't do fallthrough"
    ;;
special)
    echo -n "This does "
    ;&
fallthrough)
    echo "fall-through"
    ;;
esac

【讨论】:

  • 这是一个非常有用的提示。至少对于 Bash 4.3.11。我没有费心在其他任何人身上尝试。
  • 注意:这不适用于 bash 3.2,它仍然是 macOS 中的默认 bash。
【解决方案5】:

如果值是整数,那么您可以使用[2-3] 或者您可以将[5,7,8] 用于非连续值。

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

如果值是字符串,那么您可以使用|

#!/bin/bash
while [ $# -gt 0 ];
do
    case $1 in
    "one")
        echo "one"
        ;;
    "two" | "three")
        echo "two or three"
        ;;
    *)
        echo "others"
        ;;
    esac
    shift
done

【讨论】:

  • 最后的shift 是干什么用的?
  • shift 删除 CLI 参数列表中的第一个参数。基本上,在此循环的每次迭代中,总是使用 $1shift 的帮助下从 CLI 参数列表中获取每个参数。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-02-11
  • 1970-01-01
  • 2018-08-05
  • 1970-01-01
相关资源
最近更新 更多