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

耗尽温柔 提交于 2019-12-18 08:32:14

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!