In versions prior to 2.19, GNU grep
's -w
would only consider single-byte character alnums and underscore (so in UTF-8 locales, only the 26+26+10+1 (ASCII letters, digits and underscore)) as word constituents. So for instance echo Stéphane | grep -w St
would match. That was fixed in 2.19.
You could however implement the logic by hand:
grep -E '([^[:alnum:]_.]|^)test([^[:alnum:]_.]|$)'
That is test
preceded by either a non-word-constituent or the beginning of the line and followed by either a non-word-constituent or the end of the line.
(above [:alnum:]
matches digits and letters in your locale, not only ASCII ones, fix the locale to C if you want only ASCII ones).
If you don't want those surrounding non-word-constituents to be included in the match (for instance because you're using GNU's -o
), you can this time use PCRE regexps and look-around operators:
grep -Po '(*UCP)(?<![\w.])test(?![\w.])'
Remove (*UCP)
and add LC_ALL=C
to match only ASCII letters and digits.
Using (*UCP)
at the start of a regexp tells the PCRE library that U̲niC̲ode P̲roperties have to be used for \w
.
Without it, \w
would match your locale's alphanumericals and underscore but only for single-byte characters. That wouldn't work in UTF-8 locales (the norm nowadays) where only ASCII ones would be matched. (*UCP)
makes it work for UTF-8 as well. It would match based on PCRE's own notion of character properties which might be different from your locale's, but on GNU systems, that's just as well as the UTF-8 locale definitions there are incomplete and outdated (at least as of 2015-04).
.
and-
are already separators: from the manpage: "Word-constituent characters are letters, digits, and the underscore."