Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 857
Todd A. Jacobs Avatar asked May 22 '12 02:05

Todd A. Jacobs


People also ask

Does switch case is case sensitive?

The switch statement compares the String object in its expression with the expressions associated with each case label as if it were using the String. equals method; consequently, the comparison of String objects in switch statements is case sensitive.

Is shell script case sensitive?

Variables in Bash Scripts are untyped and declared on definition. Bash also supports some basic type declaration using the declare option, and bash variables are case sensitive.

Are switch cases case sensitive Java?

Java switch case String is case sensitive, the output of example confirms it. Java Switch case uses String. equals() method to compare the passed value with case values, so make sure to add a NULL check to avoid NullPointerException.


2 Answers

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
like image 100
Ray Toal Avatar answered Oct 01 '22 03:10

Ray Toal


It has to do with your locale settings. Specifically, the collating sequence is one with case-insensitivity.

For example, with LC_COLLATE set to en_AU.utf8 (the default on my system), you can see that it includes lowercase and uppercase together:

pax> case A in [a-b]) echo TRUE;; esac
TRUE
pax> _

but, if you get rid of the range specifier, it works as expected:

pax> case A in [ab]) echo TRUE;; esac
pax> _

That's because the first means between a and b inclusive which, for that collating sequence, includes A. For the latter means a and b only, not a range that would be affected by the collating sequence.

If you set your collating sequence to a case-sensitive one, it works as you expect:

pax> export LC_COLLATE="C"
pax> case A in [a-b]) echo TRUE;; esac
pax> 

If you just want to do this as a one-off operation without affecting anything else, you can do it in a sub-shell:

( export LC_COLLATE="C" ; case A in [a-b]) echo TRUE;; esac )
like image 34
paxdiablo Avatar answered Oct 01 '22 04:10

paxdiablo