27

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

3 Answers 3

28

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
Sign up to request clarification or add additional context in comments.

3 Comments

+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.
This is awesome! Thanks! @anubhava Why would your suggestion be better (@ instead of +)?
@anubhava Never mind, found it here. @ matches one occurrence, + matches multiple.
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.

1 Comment

@Guru is right. This only matches the first since test becomes aaa.
2

Using eval also works:

eval 'case "$1" in

    '$test')
        echo "matched"
        ;;
    *)
        echo "did not match"
        ;;
esac'

2 Comments

But eval is evil(?).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.