How to use patterns in a case statement?

Solution 1:

Brace expansion doesn't work, but *, ? and [] do. If you set shopt -s extglob then you can also use extended pattern matching:

  • ?() - zero or one occurrences of pattern
  • *() - zero or more occurrences of pattern
  • +() - one or more occurrences of pattern
  • @() - one occurrence of pattern
  • !() - anything except the pattern

Here's an example:

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

Solution 2:

I don't think you can use braces.

According to the Bash manual about case in Conditional Constructs.

Each pattern undergoes tilde expansion, parameter expansion, command substitution, and arithmetic expansion.

Nothing about Brace Expansion unfortunately.

So you'd have to do something like this:

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

Solution 3:

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

where:

  • -q prevents grep from producing output, it just produces the exit status
  • -E enables extended regular expressions

I like this because:

  • it is POSIX 7
  • it supports extended regular expressions, unlike POSIX case
  • the syntax is less clunky than case statements when there are few cases

One downside is that this is likely slower than case since it calls an external grep program, but I tend to consider performance last when using Bash.

case is POSIX 7

Bash appears to follow POSIX by default without shopt as mentioned by https://stackoverflow.com/a/4555979/895245

Here is the quote: http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_01 section "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

and then http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_13 section "2.13. Pattern Matching Notation" only mentions ?, * and [].