问题
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?
回答1:
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
回答2:
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 )
来源:https://stackoverflow.com/questions/10695029/why-isnt-the-case-statement-case-sensitive-when-nocasematch-is-off