Skip to main content
5 of 8
deleted 1 character in body
Stéphane Chazelas
  • 584.6k
  • 96
  • 1.1k
  • 1.7k

For completeness, while case has a | OR operator, it doesn't have an AND operator but if using shells with extended glob operators (ksh, zsh, bash), you can implement the AND in the pattern syntax:

  • ksh93's @(x&y&z) operator:

      case $string in
        ( @({12}(?)&~(i:[aeiou]*)&*[0123456789]) )
          echo is 12 characters long AND starts with a vowel AND ends in a decimal
      esac
    
  • zsh (using ~ (AND-NOT) combined with ^ (NOT)): x~^y~^z

      set -o extendedglob
      case $string in
        ( ?(#c12)~^(#i)[aeiou]*~^*[0-9] )
          echo is 12 characters long AND starts with a vowel AND ends in a decimal
      esac
    
  • ksh88, bash, using double negation with OR (!(!(x)|!(y)|!(z)))

      shopt -s extglob # bash only
      case $string in
        ( !(!(????????????)|!([aAeEıiIİoOuU]*)|!(*[0123456789])) )
          echo is 12 characters long AND starts with a vowel AND ends in a decimal
      esac
    

In any case, remember that except in zsh where ranges are always based on codepoint values, ranges like [0-9] cannot be used reliably outside of the POSIX/C locale (hence the [0123456789] instead above).

ksh93 and zsh's case insensitive matching operators (~(i) and (#i)) honour the locale for case sensitive comparison. For instance, in a Turkish locale on a GNU system, (#i)[aeiou] will match on İ, but not I (because uppercase i is İ there). To get a consistent outcome regardless of the locale, you may want to hard code all possible values instead like in the ksh88/bash approach.

Stéphane Chazelas
  • 584.6k
  • 96
  • 1.1k
  • 1.7k