Search code examples
bashpattern-matchingcase-sensitive

Why isn't the case statement case-sensitive when nocasematch is off?


Given the following:

$ echo $BASH_VERSION
4.2.10(1)-release

$ shopt | fgrep case
nocaseglob      off
nocasematch     off

$ case A in [a-z]) echo TRUE;; esac
TRUE

I expect that the capital letter A should not match the lower-case character class of [a-z], but it does. Why doesn't this match fail?


Solution

  • You can't reliably use the dash this way. If I don't use dashes, it works as expected:

    $ bash --version
    GNU bash, version 4.2.10(1)-release (x86_64-pc-linux-gnu)
    Copyright (C) 2011 Free Software Foundation, Inc.
    License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
    
    This is free software; you are free to change and redistribute it.
    There is NO WARRANTY, to the extent permitted by law.
    $ shopt -s nocasematch
    $ case A in [abc]) echo TRUE;; esac
    TRUE
    $ shopt -u nocasematch
    $ case A in [abc]) echo TRUE;; esac
    $ 
    

    But with dashes, it prints TRUE regardless of the setting of nocasematch.

    Bash is doing pattern matching here. Check out this section of the reference manual where it says that using the hyphen MIGHT interpret [a-z] as [A-Za-z]! It tells you how to get the traditional interpretation (set LC_COLLATE or LC_ALL to C). Basically your default locale is sorting in dictionary order. The reference manual explains things pretty well.

    ADDENDUM

    Okay I have a transcript for you.

    $ shopt -u nocasematch
    $ case A in [a-z]) echo TRUE;; esac
    TRUE
    $ shopt -s nocasematch
    $ case A in [a-z]) echo TRUE;; esac
    TRUE
    $ LC_ALL=C
    $ shopt -u nocasematch
    $ case A in [a-z]) echo TRUE;; esac
    $ shopt -s nocasematch
    $ case A in [a-z]) echo TRUE;; esac
    TRUE