7

we set the following variables

status=ok
echo $status
ok

now we want to verify if variables with regex will match

as the following

[[ $status =~ [OK]  ]] && echo "is the same"
[[ $status =~ OK  ]] && echo "is the same"
[[ $status =~ "OK"  ]] && echo "is the same"

but any of the above not print "is the same"

what is wrong in my regex?

16

[OK] Will match either character within the brackets, the brackets do not tell it to be case insensitive.

You could do:

[[ "$status" =~ ^[Oo][Kk]$ ]]

or I would probably do the following:

[[ "${status,,}" == ok ]]

The ,, operator for parameter expansion will convert the entire variable to lowercase for the purpose of the comparison.

| improve this answer | |
10

[[ $status =~ OK ]] (or [[ $status =~ "OK" ]]) matches if $status contains OK, and [[ $status =~ [OK] ]] matches if it contains a character in that OK set, so either O or K.

With regular expressions you need to use the ^ or $ to anchor the pattern respectively at the start and end of the subject if you want to match the subject as a whole and not within it.

To do a case insensitive match in bash, you can use the nocasematch option:

That applies to shell pattern matching with Korn-style [[ $var = pattern ]] or standard case $var in (pattern) and to regexp matching with [[ $var =~ regexp ]].

So, here you could do:

shopt -s nocasematch
[[ $status = ok ]] && echo yes
[[ $status =~ ^ok$ ]] && echo yes
case $status in
  (ok) echo yes
esac

(you'll probably want to unset nocasematch afterwards or reset it to its previous value (see typeset restore="$(shopt -p nocasematch)" to save, and eval "$restore" to restore) as leaving it on would affect all pattern matching operations).

Or you could use:

[[ $status = [oO][kK] ]] && echo yes
[[ $status =~ ^[oO][kK]$ ]] && echo yes
case $status in
  ([oO][kK]) echo yes
esac
case $status in
  (ok | OK | Ok | oK) echo yes
esac

The case based variants being standard POSIX sh syntax.

In the zsh shell, instead of turning the global nocasematch option globally (and pervert all pattern matching operators), you could use extended globbing operators or PCRE regexp operators that selectively enable case-insensitive matching for a single pattern or portion of a single pattern.

For instance,

set -o extendedglob
[[ $status = (#i)ok ]]

Or:

zmodload zsh/pcre
[[ $status -pcre-match '^(?i)ok$' ]]

Or for the equivalent of bash's ${var,,}, use $var:l à la csh or ${(L)var}: [ "$status:l" = ok ]

In zsh, you'd want to avoid using a variable named $status as that's the variable that holds the exit status of the previous command as an alias of the Bourne-style $? like in most non-Bourne shells (csh, tcsh, rc, es, fish at least).

In the ksh93 variant of the Korn shell (whose [[...]] both bash and zsh have copied), you'd do [[ $status = ~(i)ok ]].

| improve this answer | |
  • 1
    @Toby, see edit, but note that in any case, since bash can't do scoping for its shopt options, let alone static scoping, doing it safely in all cases is almost impossible. For instance, what if there are some DEBUG/ERR/SIG traps that use pattern matching, what if echo has been redefined as a function, what if that code is in a function meant to be reentrant... – Stéphane Chazelas Nov 12 at 8:11
4

You could do pattern matching like this:

[[ $status == @(ok|OK|okay) ]] && echo "is the same"

Or, similarly to jesse_b's idea in the previous post, the^^ operator for parameter expansion will convert the entire variable to UPPER-case for the purpose of the comparison:

[[ "${status^^}" == OK ]] && echo "is the same"
| improve this answer | |
  • 1
    ITYM @(...) instead of ?(...) (as ?(...) would match on the empty string). Note that it assumes bash 4.1 or above or that the extglob option be enabled. – Stéphane Chazelas Nov 11 at 6:07
  • 1
    @Stéphane Chazelas: You just have to be the buzz-kill on any answer, don't you? :-)) But when you're right, you're right. – Ardwena Nov 11 at 6:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy