26

I'm trying to write a Bash script that uses a variable as a pattern in a case statement. However, I just cannot get it to work.

Case statement:

case "$1" in
    $test)
        echo "matched"
        ;;
    *)
        echo "didn't match"
        ;;
esac

I've tried this with assigning $test as aaa|bbb|ccc, (aaa|bbb|ccc), [aaa,bbb,ccc] and several other combinations. I also tried these as the pattern in the case statement: @($test), @($(echo $test)), $($test). Also no success.

For clarity, I would like the variable to represent multiple patterns like this:

case "$1" in
    aaa|bbb|ccc)
        echo "matched"
        ;;
    *)
        echo "didn't match"
        ;;
esac
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
siebz0r
  • 18,867
  • 14
  • 64
  • 107

3 Answers3

25

You can use the extglob option:

#! /bin/bash

shopt -s extglob         # enables pattern lists like @(...|...)
test='@(aaa|bbb|ccc)'

for x in aaa bbb ccc ddd ; do
    echo -n "$x "
    case "$x" in
        $test) echo Matches.
        ;;
        *) echo Does not match.
    esac
done
choroba
  • 231,213
  • 25
  • 204
  • 289
  • 2
    +1 for reminding me the use of `extglob`. By the way `test='@(aaa|bbb|ccc)'`also works and is probably better option in this case. – anubhava Nov 06 '12 at 16:14
  • This is awesome! Thanks! @anubhava Why would your suggestion be better (@ instead of +)? – siebz0r Nov 06 '12 at 16:19
  • 1
    @anubhava Never mind, found it [here](https://www.gnu.org/software/bash/manual/html_node/Pattern-Matching.html#Pattern-Matching). @ matches one occurrence, + matches multiple. – siebz0r Nov 06 '12 at 16:22
3

Here's something a bit different:

#!/bin/bash

pattern1="aaa bbb ccc"
pattern2="hello world"
test=$(echo -e "$pattern1\n$pattern2" | grep -e $1)

case "$test" in
    "$pattern1")
        echo "matched - pattern1"
        ;;
    "$pattern2")
        echo "matched - pattern2"
        ;;
    *)
        echo "didn't match"
        ;;
esac

This makes use of grep to do the pattern matching for you, but still allows you to specify multiple pattern sets to be used in a case-statement structure.

For instance:

  • If either aaa, bbb, or ccc is the first argument to the script, this will output matched - pattern1.
  • If either hello or world is the first argument, this will output matched - pattern2.
  • Otherwise it will output didn't match.
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
sampson-chen
  • 45,805
  • 12
  • 84
  • 81
2

Using eval also works:

eval 'case "$1" in

    '$test')
        echo "matched"
        ;;
    *)
        echo "did not match"
        ;;
esac'
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
mliberi
  • 29
  • 2