Multiple conditions in a CASE statement

is it possible to use multiple conditions in a CASE statement? And if so, what is the syntax? I'm trying to use one but can't seem to get it right. I want the statement to be

CASE $vendor OR $alias
    condition 1)  statements;
    condition 2) statements;
    etc.
esac

but I keep getting syntax errors, no matter what I try. Can somene tell me what the right syntax is

How about this?

CASE $vendor  in
    condition 1|condition 3)  statements;;
    condition 2|condition 4) statements;;
    etc.
esac

Combine the two vars with a seperator eg for green yellow red conditions:

CASE ${vendor}+${alias} in
    *+green|green+*) statements;;
    *+yellow|yellow+*)  statements;;
    *+red|red+*)  statements;;
  etc.
esac

Chubler --

I'm not sure how to interpret that statement. What I want to do is have the CASE statement test the value of the variables. So, for example I need to have the statements executed if either vendor or alias is the value in the subsequent statements. Is that what your answer means? My script, at this point, is allowing the user to enter values for two variables (as you can see), but needs to test if either of them are p, m or e, in which case the script goes back to a previous menu or exits the script altogether.

Yes that is what the example I posted is doing.

To explain the values of the two variables are joined together with a + in between. (For example green+black )

The case statement *+green|green+*) will match green+black (but not yellow+black)

So for your example just replace green with m ; yellow with p and red with e:

case ${vendor}+${alias} in
    *+m|m+*) // go back to main;;
    *+p|p+*) // go to previous ;;
    *+e|e+*) // exit menu;;
 etc.
esae

Thanks -- so let me see if I understand, just to be clear. The help command doesn't say anything about the + sign, nor does the bash book I have.

Just to be clear, the statement means 'Check the value of both vendor and alias. [If vendor is not one of the test criteria and is followed or preceded by the test conditions ] OR [Alias is not one of the test criteria and is followed by any of the test criteria], then execute the corresponding commands. Is that correct ?

One more thing -- how would it be written if I wanted it to check for upper and lower case, which Is what I want to do.

The + sign used here isn't anything special to the shell it's just a char we have thrown inbetween the two variables. One could just as well use "_" or "," as long as the character isn't in the strings being tested.

What is happening is the two strings are joined together and then the glob pattern matching capabilites of the case statement are used to match what is required.

So for upper or lower case and using "_" we would have:

case ${vendor}_${alias} in
    *_[Mm]|[Mm]_*) // go back to main;;
    *_[Pp]|[Pp]_*) // go to previous ;;
    *_[Ee]|[Ee]_*) // exit menu;;
etc.
esae

The expression "*_[Mm]|[Mm]_*" equates to:

    <zero or more chars>_<upper or lower case M> ..or..
    <upper or lower case M>_<zero or more chars>

Some example strings that will match this are:

    M_NotImportant
    m_
    m_back to main
    back to main_M

Chubler,

Nice solution for multiple variable matching. The only thing I'd add would be to note that these are 'glob' matching patterns rather than 'regex' patterns for other readers.

1 Like

Thanks. I thought that case was an alternate type of if-then-else statement, but you're telling me that you can test a string against certain patterns, and in this case, the string contains the values of the user entered variables?

One more thing -- how would one test for no value entered for a variable -- the null string?

Yes, as you can see case has powerfull glob pattern matching (thanks for the correction m1xram) that makes it usefull in all sorts of ways beyond simple if-then-else support.

Testing for null values:

case ${vendor}_${alias} in
    _) echo Both null;;
    _*)  echo Vendor null;;
    *_)  echo Alias null;;
esac

PS: In case, you can usually use both ( and ) around your patterns, which is prettier if not as ancient, preserving many other nice features like the % in vi, ksh $(...), subshell (...).

Chubler -- can you tell me what the difference is between glob patterns and regex patterns?

Regex pattern '.' is glob pattern '?', '.' is '', '[...]' in glob has no negative list '[^...]', '.' is literal in glob, and then it gets muddy as even glob has some more advanced=less reliably available extensions. Glob is a bit like extended regex (egrep), but weaker. In case it is common to OR like egrep:

 
case "$a" in
(AAA|BBB|CCC)
  .
  .
  .
  ;;
([A-C][ABC][CAB])
  .
  .
  .
  ;;
esac

I'm sorry, but I don't understand -- can you be a little more clear?

  • In glob, ? matches any single character, and in regex . does the same.
  • In glob, * matches any 0-max characters, and in reges .* doees that.
  • In glob you can match any character in a list, with ranges, like characters legal for C variable names: [a-zA-Z0-9_] Regex does the same, the same way but can also do negative lists, like not a number: [^0-9].
  • In regex you have * for any count, but not in glob.
  • Extended regex, like egrep or grep -E, has + for count 0 or one, \{##\} for specific count, and \{##-##\} for ranges of count.
  • Extended regex has parentheses and OR operator | for lists of alternatives, and glob in case does the same: From (Tom|Dick|Harry).
  • Extended regex has morphed in ways that make old scripts break, like for beginning of word \< disappeared and \b came in its place for the position at the edge of a word. One friend speculates that the PERL lovers had their way over traditional UNIX thought.
  • Apparently bash has extended globbing available, too. As I recall, the context can be switched between regex and glob with different wrapping operators in if/while tests.

So when would you glob and when would you use regular expressions? I'm still somewhat confused.:confused:

I think I get it -- glob is used for finding filenames and regex is used for matching strings (as in a piece of text)?

More information.

Most things can be found on the command line with 'man'. Try 'man bash' and then search for Pattern Matching with '/Pattern Matching'. Also try 'man grep' and read through the section about REGULAR EXPRESSIONS.

I did a search of the output from 'man bash' with '/regex' and it mentioned the regular expression matching operator '=~', also used in PERL. It says 'matched accordingly (as in regex(3))'. This means I can look up the information with 'man 3 regex' assuming I have the man pages installed from Linux Documentation Project.

Glob patterns can (and usually do) match against filenames. But glob patterns in case options and shell if expressions are tested against strings not filenames eg:

$ [[ "salad" == s* ]] && echo yes
yes
$ [[ "salad" == s.* ]] && echo yes
$ [[ "s.jpg" == s.* ]] && echo yes
yes

Many languages allow you to use both glob and regex to match strings. PERL, TCL, and Java are a few examples.