Introduction
Yes. grep can print only the matched part of a line instead of the whole line by using the -o option. This is the usual answer when you want only matching words, tokens, or substrings from input rather than the full surrounding text.
The Basic Option: grep -o
By default, grep prints entire lines that contain a match. The -o flag changes that behavior and prints each match on its own line.
printf 'error code=42\nwarning code=99\n' | grep -o 'code=[0-9]*'
Output:
This works whether the input comes from a file, a pipeline, or command output.
grep -o 'pattern' app.log
If a line contains multiple matches, grep -o prints each one separately.
Matching Whole Words
If by "only words" you mean whole-word matches rather than substrings inside larger words, add word-boundary behavior. One simple option is -w.
printf 'cat scatter catalog cat\n' | grep -o -w 'cat'
Output:
Without -w, the pattern cat would also match inside scatter and catalog.
Another approach is to write an explicit regular expression:
printf 'cat scatter catalog cat\n' | grep -E -o '\<cat\>'
Different systems vary a little in regex support, so -w is often the simplest choice when it fits your needs.
grep -o is especially useful when the pattern itself represents the token you want to extract.
For example, to pull email-like strings from text:
printf 'Contact [email protected] or [email protected]\n' \
| grep -E -o '[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}' ``` Or to pull identifiers that start with `user_`: ```bash printf 'user_12 admin user_99 guest\n' | grep -E -o 'user_[0-9]+' ``` In both cases, the surrounding line content is ignored and only the matched tokens are printed. ## Files, Recursion, and File Names You can combine `-o` with normal file searching options. For example, recursive search still works: ```bash grep -R -o -E 'TODO|FIXME' src/ ``` If you also want the file name, do not use `-h`: ```bash grep -R -o -E 'TODO|FIXME' src/ ``` Typical output looks like: ```text src/app.js:TODO src/db.js:FIXME ``` If you want only the matches without file names, add `-h`: ```bash grep -R -h -o -E 'TODO|FIXME' src/ ``` ## When `grep` Is Not Enough Sometimes people really want capture groups, not the full matched text. Standard `grep -o` prints the entire match, not an arbitrary subgroup from the regex. In those cases, tools such as `sed`, `awk`, `perl`, or `ripgrep` with PCRE-style features may be a better fit. For example, if the input is `id=123` and you want only `123`, you can just match the numeric part directly: ```bash printf 'id=123 status=ok\n' | grep -o '[0-9]\+' ``` But if the extraction rule becomes more complex than "match the exact thing I want printed," another text-processing tool may be more maintainable. ## Common Pitfalls - Forgetting `-o` and wondering why `grep` still prints whole lines. - Using a loose pattern that also matches text inside larger words when `-w` is needed. - Expecting `grep -o` to print only a capture group rather than the whole regex match. - Assuming every `grep` implementation supports exactly the same regex extensions. - Writing a pattern that is too broad and producing repeated partial matches you did not intend. ## Summary - Use `grep -o` to print only the matched text instead of full lines. - Add `-w` when you need whole-word matches. - Combine `-o` with `-E` for more expressive regular expressions. - Match the exact token you want printed, because `grep -o` outputs the whole match. - Switch to another text tool when you need more advanced extraction than plain `grep` provides.