如何在case语句中使用模式?

104

man页面说明case语句使用“文件名扩展模式匹配”。

通常我想要为一些参数设置短名称,所以我会这样写:

case $1 in
    req|reqs|requirements) TASK="Functional Requirements";;
    met|meet|meetings) TASK="Meetings with the client";;
esac

logTimeSpentIn "$TASK"

我尝试使用像req*me{e,}t这样的模式,我知道它们会正确扩展以匹配文件名扩展上下文中的那些值,但它不起作用。

3个回答

207

花括号扩展无效,但星号(*)、问号(?)和方括号([])有效。如果设置 shopt -s extglob ,则还可以使用 扩展模式匹配

  • ?() - 匹配零个或一个模式
  • *() - 匹配零个或多个模式
  • +() - 匹配一个或多个模式
  • @() - 匹配一个模式
  • !() - 匹配除了该模式以外的任何内容

这里是一个例子:

shopt -s extglob
for arg in apple be cd meet o mississippi
do
    # call functions based on arguments
    case "$arg" in
        a*             ) foo;;    # matches anything starting with "a"
        b?             ) bar;;    # matches any two-character string starting with "b"
        c[de]          ) baz;;    # matches "cd" or "ce"
        me?(e)t        ) qux;;    # matches "met" or "meet"
        @(a|e|i|o|u)   ) fuzz;;   # matches one vowel
        m+(iss)?(ippi) ) fizz;;   # matches "miss" or "mississippi" or others
        *              ) bazinga;; # catchall, matches anything not matched above
    esac
done

3
以下是链接到有关此内容的文档:https://www.gnu.org/software/bash/manual/html_node/Pattern-Matching.html#Pattern-Matching - phyatt
@phyatt:谢谢。我已将链接添加到我的答案中。 - Dennis Williamson
1
这个答案对我很有帮助,因为我把我的模式用双引号("a*")括起来,但那并没有起作用。 - wytten
1
一些版本的bash即使启用了shopt -s extglob,也不支持@(...) - Yzmir Ramirez
@YzmirRamirez:我很好奇是哪些版本。extglob自bash-2.02-alpha1(约1998年)以来就一直存在于Bash中。 - Dennis Williamson
@phyatt,那个链接帮助我解决了一个更复杂的“case”问题。 - RonJohn

49

我认为你不能使用花括号。

根据关于条件结构的Bash手册。

每个模式都经历了波浪线扩展、参数扩展、命令替换和算术扩展。

遗憾的是,没有关于花括号扩展的内容。

所以你需要像这样做:

case $1 in
    req*)
        ...
        ;;
    met*|meet*)
        ...
        ;;
    *)
        # You should have a default one too.
esac

9

if and grep -Eq

arg='abc'
if echo "$arg" | grep -Eq 'a.c|d.*'; then
  echo 'first'
elif echo "$arg" | grep -Eq 'a{2,3}'; then
  echo 'second'
fi

其中:

  • -q 防止 grep 产生输出,它只产生退出状态
  • -E 启用扩展正则表达式

我喜欢这个的原因是:

  • 它符合 POSIX 7 标准
  • 支持扩展正则表达式,不像 POSIX 的 case
  • 当有少量情况时,语法比 case 语句更简洁

一个缺点是,这可能比 case 慢,因为它调用了外部的 grep 程序,但我使用 Bash 时通常将性能视为最后考虑的因素。

case 符合 POSIX 7 标准

Bash 默认遵循 POSIX,无需使用 shopt,如https://dev59.com/NG455IYBdhLWcg3wFP9u#4555979所述

这里是引用:http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_01 章节“Case Conditional Construct”:

The conditional construct case shall execute the compound-list corresponding to the first one of several patterns (see Pattern Matching Notation) [...] Multiple patterns with the same compound-list shall be delimited by the '|' symbol. [...]

The format for the case construct is as follows:

case word in
     [(] pattern1 ) compound-list ;;
     [[(] pattern[ | pattern] ... ) compound-list ;;] ...
     [[(] pattern[ | pattern] ... ) compound-list]
  esac

然后,http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_13 的 "2.13.模式匹配符号" 部分仅提到了 ?*[]


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接