ScreenshotNeo

BlogGuides

16 Practical grep Command Examples

Learn 16 practical GNU grep examples for literal text, regex, recursive searches, pipelines, context, scripts, and safe edge-case handling.

By the ScreenshotNeo team1 October 20267 min read

grep searches input for lines matching a pattern and prints the matching lines by default. Start by choosing whether your pattern is literal text (-F) or a regular expression (the default basic regex mode, or -E for extended regex), then choose the output you need: lines, line numbers, counts, filenames, context, or only the matched text.

The examples below use GNU grep 3.12 syntax. Options such as --include and some behavior described here are GNU extensions; check your platform’s manual when portability matters. See the GNU Grep manual and the POSIX grep specification.

Quick option guide

Need Option Example
Ignore case -i grep -i 'error' app.log
Literal text -F grep -F 'price: $5.00' app.log
Extended regex -E grep -E 'ERROR|FATAL' app.log
Line numbers -n grep -n 'timeout' app.log
Invert matches -v grep -v 'DEBUG' app.log
Count matching lines -c grep -c 'WARN' app.log
Filenames only -l grep -l 'main' ./*.c
Matched text only -o grep -oE '[0-9]{3}-[0-9]{4}' contacts.txt
Nearby lines -C 2 grep -C 2 'Exception' app.log
Recursive search -r grep -r -n 'TODO' ./project

16 practical grep examples

1. Find a simple string

grep 'ERROR' app.log

This prints every line in app.log containing ERROR. Patterns are regular expressions by default, but this pattern contains no regex metacharacters, so it behaves like a literal match.

2. Ignore case

grep -i 'error' app.log

-i matches error, Error, and ERROR. Use it for human-entered text or logs whose capitalization is inconsistent.

3. Search for literal punctuation

grep -F 'price: $5.00' app.log

-F selects fixed-string mode. Dollar signs, periods, brackets, and other punctuation are treated literally, which is usually clearest when searching for text copied from a log.

4. Match a whole word

grep -w 'cat' notes.txt

GNU grep’s -w checks word boundaries using its documented word-constituent rules, so it does not match cat inside concatenate. Test unusual punctuation and language-specific text against the exact input you have.

5. Match either of two alternatives

grep -E 'ERROR|FATAL' app.log

-E enables extended regular expressions, including the alternation operator |. Quote the pattern so the shell passes it unchanged.

6. Match the beginning of a line

grep '^2026-' app.log

The caret anchors the pattern to the start of each line. Replace 2026- with the prefix relevant to your data.

7. Show line numbers

grep -n 'timeout' app.log

-n adds each match’s one-based line number, which is useful when opening the file in an editor or reporting a failure.

8. Print only the matching part

grep -oE '[0-9]{3}-[0-9]{4}' contacts.txt

With GNU grep, -o prints each nonempty matched portion on its own line. This is useful for extracting identifiers from otherwise noisy lines.

9. Count matching lines

grep -c 'WARN' app.log

-c prints the number of matching lines. It counts lines, not every occurrence when a line contains the pattern more than once.

10. Print lines that do not match

grep -v 'DEBUG' app.log

-v inverts selection. This removes debug lines from a stream while retaining every other line.

11. List only filenames with a match

grep -l 'main' ./*.c

-l prints the name of each file containing at least one match, rather than printing matching content. Use -L to list files with no match.

12. Show surrounding context

grep -C 2 'Exception' app.log

-C 2 shows two lines before and after each matching line. Use -B 2 for before-only context or -A 2 for after-only context.

13. Search a directory tree

grep -r -n 'TODO' ./project

-r recursively visits files below ./project, and -n preserves useful line locations. Add -I when you want GNU grep to skip binary files.

14. Restrict recursive search to selected file types

grep -r -n --include='*.c' 'main' ./src

--include is a GNU option that limits recursive traversal results to matching filenames. For several types, repeat it:

grep -r -n --include='*.c' --include='*.h' 'main' ./src

For more precise selection, compose find with grep:

find ./src -type f \( -name '*.c' -o -name '*.h' \) -exec grep -nH 'main' {} +

15. Filter command output through a pipe

journalctl -u example.service | grep -i 'failed'

When no filename is supplied, grep reads standard input. The availability and permissions of journalctl depend on the operating system; substitute any command that produces text.

16. Safely handle patterns and filenames beginning with -

grep -e "$pattern" ./*

-e explicitly marks the next argument as a pattern, while ./* expands filenames with a path prefix so they are not mistaken for options. You can also use -- as an option terminator:

grep -- "$pattern" ./file.txt

The GNU manual documents a caveat for a file literally named -; use an explicit path such as ./- when that case matters.

Literal search versus regular expressions

Use -F when the input is an exact snippet. It avoids escaping regex punctuation and communicates intent. GNU grep’s default is basic regular expressions (-G); use -E for readable alternation, grouping, and repetition. GNU’s -P requests PCRE-style matching, but it is not a portable default and may be unavailable on another implementation.

Mode Best for Portability
-F Exact text and copied punctuation POSIX
default / -G Basic regular expressions POSIX
-E Alternation and extended expressions POSIX
-P PCRE-specific syntax GNU-specific and implementation-dependent

Shell quoting and filename safety

  • Quote patterns such as '*.c', '$5.00', and 'ERROR|FATAL' so the shell does not expand or reinterpret them.
  • Shell globs and grep regexes are separate syntaxes: *.c selects filenames, while a grep pattern describes line content.
  • Use -e or -- when a pattern can begin with a hyphen.
  • Prefer ./file or an absolute path for filenames beginning with -.

Exit statuses in scripts

GNU grep exits with status 0 when it selects at least one line, 1 when it selects none, and 2 for an error. A no-match result is therefore not the same as a failed command.

if grep -qF 'READY' status.txt; then
  echo 'ready'
elif [ "$?" -eq 1 ]; then
  echo 'not ready'
else
  echo 'grep error' >&2
  exit 2
fi

This distinction matters with set -e, where an expected no-match status can stop a script. Quiet mode has documented special behavior when a match is found even if an error was also detected, so check the manual when combining -q with large or changing inputs.

Performance and reliability checklist

  • Use -F for literal searches; it avoids regex parsing and accidental metacharacters.
  • Limit traversal with a starting directory, --include, or find rather than scanning an entire filesystem.
  • Use -l when you only need filenames and -q when you only need a yes/no result.
  • Expect permission errors, unreadable files, binary data, changing files, and remote or mounted filesystem delays.
  • Use -nH in multi-file reports when both line numbers and filenames are needed.
  • For portable scripts, stick to POSIX options and verify GNU-only flags on the target host.

Troubleshooting common grep errors

Symptom Cause Fix
No output No line matched, or the pattern was altered by shell expansion Check status $?, quote the pattern, and try -n or -F.
grep: invalid option A pattern or filename starts with - Use -e "$pattern", --, or a ./ path.
Regex matches too much Basic or extended regex metacharacters were unintended Use -F for literal text and quote the pattern.
Recursive search misses files Filename filter, permissions, symlink behavior, or binary content Review --include, permissions, and whether the files are symlinks or binary.
Binary file matches Input contains binary bytes Decide whether to skip it, inspect it separately, or use an option appropriate to your GNU grep version.
Script stops on no match set -e treats status 1 as failure Handle statuses explicitly as shown above.
journalctl fails The command is unavailable or access is denied Use another text-producing command or obtain the required permissions.

Or skip the browser setup

If your next step is turning a URL into an image for documentation, tests, or an agent workflow, ScreenshotNeo provides a single GET request instead of maintaining browser automation. It accepts consent banners before capture and removes more than 60 known consent platforms, newsletter popups, and chat widgets. Bot checks, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers identify the page verdict and billing result.

See the ScreenshotNeo API documentation for all options.

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);

ScreenshotNeo also includes an MCP server with take_screenshot, get_page_info, and capture_pdf tools for Claude, Cursor, and other MCP clients. The free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000. Create a free ScreenshotNeo account.

FAQ

Does grep search filenames or file contents?

It searches file contents. Shell globs, --include, and find determine which filenames are supplied.

What does grep print when nothing matches?

Normally nothing on standard output, with exit status 1. Treat that as a valid no-match result in scripts.

Should I use -r or -R?

Use the recursive option supported by your implementation and read its manual for symlink behavior. GNU-specific workflows should document the exact option and version.

Why did my dollar sign or brackets behave strangely?

The shell and regex engine both assign meaning to punctuation. Quote the pattern, then choose -F when you need an exact literal.