This fixes echo Y | LC_ALL=en_US.UTF-8 grep -i '[y]' The expected output is: Y Without this patch, it works on non UTF-8 environment, but fails on UTF-8 environment. The definition of RE_ICASE comes from the glibc (/usr/include/regex.h) Maybe lib/posix/regex.h should be removed to enforce the usage of the glibc's regex.h --- a/lib/posix/regex.h.orig 2004-01-05 12:09:12.984391131 +0000 +++ b/lib/posix/regex.h 2004-01-05 12:09:24.717990622 +0000 @@ -109,6 +109,10 @@ treated as 'a\{1'. */ #define RE_INVALID_INTERVAL_ORD (RE_DEBUG << 1) +/* If this bit is set, then ignore case when matching. + If not set, then case is significant. */ +#define RE_ICASE (RE_INVALID_INTERVAL_ORD << 1) + /* This global variable defines the particular regexp syntax to use (for some interfaces). When a regexp is compiled, the syntax used is stored in the pattern buffer, so changing this does not affect --- a/src/search.c 2009-02-11 17:15:24.000000000 +1100 +++ b/src/search.c 2009-02-11 17:23:48.000000000 +1100 @@ -172,10 +172,8 @@ char const *motif = pattern; check_utf8 (); -#if 0 if (match_icase) syntax_bits |= RE_ICASE; -#endif re_set_syntax (syntax_bits); dfasyntax (syntax_bits, match_icase, eolbyte);