/flags/grep/grep-w-word-regexp
grep -w: match whole words only
- tool
- grep
- command
- grep
- flag
- -w, --word-regexp
- default
- off (the pattern may match inside longer words)
grep -w word file prints only lines where the pattern matches as a whole word, so grep -w cat finds the cat sat but not catalog or bobcat. A match counts as a word when the characters before and after it are not word constituents: letters, digits and the underscore. The start and end of the line also count as boundaries.
Without and with -w
printf 'cat\ncatalog\nthe cat sat\nbobcat\ncat_name\ncat-food\n' > words.txt
grep cat words.txt
echo '--- with -w'
grep -w cat words.txt
echo '--- with -x (whole line)'
grep -x cat words.txtOutput
cat catalog the cat sat bobcat cat_name cat-food --- with -w cat the cat sat cat-food --- with -x (whole line) cat
cat_name is excluded because _ is a word character; cat-food is included because - is not. This is the most common surprise when searching code: grep -w user does not match user_id, but does match user-id and user.name.
How -w compares with similar options
| Command | Matches |
|---|---|
| grep cat | Any line that contains cat, also inside catalog or bobcat |
| grep -w cat | cat as a whole word, delimited by non-word characters |
| grep '\bcat\b' | Same as -w in GNU grep (word boundary escapes) |
| grep '\<cat\>' | GNU start and end of word anchors, same effect |
| grep -x cat | Only lines that are exactly cat |
| grep -wF cat | Whole word, pattern taken literally |
-w applies to the whole match
With a regex, -w checks the boundaries of the text the pattern matched, not of each piece:
printf 'cat\ncot\ncoat\nscatter\n' > c.txt
grep -w 'c.t' c.txt
echo '--- several words in one search'
printf 'error found\nerrors found\nno problem\nwarning: disk\n' > log.txt
grep -wE 'error|warning' log.txtOutput
cat cot --- several words in one search error found warning: disk
c.t matched cat and cot only; coat does not fit the pattern and scatter contains cat inside a longer word. With -E and an alternation, each alternative still has to be a whole word, so errors is not matched.
Pitfalls
- Non-ASCII letters. Whether
écounts as a word character depends on the locale. UnderLC_ALL=C, accented letters are boundaries. - Patterns that start or end with punctuation. The check is made on the characters around the match, so
grep -w -e '-v'still findsuse -v here: the spaces around it are boundaries. - Not for identifiers with dots.
grep -w configmatchesconfig.yaml, since the dot is a boundary. - Exit status. As with any grep, exit 1 means no line matched and 2 means an error, such as an unreadable file. In scripts combine with
-qto test without output.
-w is not in POSIX, but GNU grep, BSD grep on macOS and BusyBox all support it.
FAQ
Why does grep -w cat match cat-food but not cat_name?
grep -w treats letters, digits and the underscore as word characters. In cat_name the underscore continues the word, so there is no match; in cat-food the hyphen is not a word character, so cat is a whole word there and the line matches.
What is the difference between grep -w and grep -x?
-w requires the match to be a whole word anywhere in the line. -x requires the match to be the entire line. grep -x cat matches only a line that is exactly cat.
Is grep -w the same as \b in the pattern?
For simple words they give the same result in GNU grep: grep '\bcat\b' and grep -w cat match the same lines. -w is portable to BSD grep and works with -F fixed strings, where \b would be taken literally.