/commands/grep/grep-context-lines
grep -A -B -C: show lines before and after each match
- tool
- grep
- versions
- GNU grep 3.x
- os
- linux, macos, windows
grep -A 3 pattern file prints each matching line and the 3 lines after it, -B 3 the 3 lines before it, and -C 3 3 lines on both sides. Add -n to see line numbers: matching lines use : after the number and context lines use -, so you can tell them apart. When two groups of context are not adjacent, grep prints a -- separator line between them.
Example
cat > app.log <<'EOF'
start
loading config
ERROR config missing key
retrying
connected
idle
idle
ERROR timeout
stopping
EOF
grep -n -A 1 ERROR app.log
echo ===
grep -n -B 2 'ERROR timeout' app.log
echo ===
grep -C 1 --no-group-separator ERROR app.logOutput
3:ERROR config missing key 4-retrying -- 8:ERROR timeout 9-stopping === 6-idle 7-idle 8:ERROR timeout === loading config ERROR config missing key retrying idle ERROR timeout stopping
In the first command each ERROR line is followed by one line of context, and -- separates the two groups. In the second, -B 2 shows what happened just before the timeout. The third prints one line on each side and drops the separator.
Options
| Option | Effect |
|---|---|
| -A N, --after-context=N | N lines after each match |
| -B N, --before-context=N | N lines before each match |
| -C N, --context=N, -N | N lines before and after; -2 is the same as -C 2 |
| -n | Line numbers; 12: for a match, 12- for a context line |
| --group-separator=TEXT | Print TEXT instead of -- between groups (GNU) |
| --no-group-separator | No line between groups (GNU) |
| -m N | Stop after N matching lines; trailing context is still printed |
| --color=always | Highlight the match, also when the output goes to a pipe such as less -R |
How overlapping context is handled
When the context of two matches overlaps or touches, grep merges them into one group and prints each line once; there is no -- between them. This is why -C 5 on a log with many matches can print long blocks without separators. If every match must be shown with its own context, use a different tool (for example awk) because grep never repeats lines.
Context in several files
printf 'a\nTODO fix\nb\n' > one.txt
printf 'c\nd\nTODO test\n' > two.txt
grep -n -B 1 TODO one.txt two.txtOutput
one.txt-1-a one.txt:2:TODO fix -- two.txt-2-d two.txt:3:TODO test
With more than one file, every line starts with the file name. Matching lines use file:line: and context lines file-line-, which keeps the output parseable.
Platform notes
The options above are in GNU grep and in the BSD grep that ships with macOS; -A, -B and -C are not in POSIX, so very small systems (BusyBox builds without them) may lack them. If no line matches, grep prints nothing and exits with status 1, whatever the context options.
FAQ
How do I remove the -- lines between groups?
GNU grep prints -- between groups of context that are not adjacent. Add --no-group-separator to drop them, or --group-separator=TEXT to print something else. Both are GNU options; with another grep, filter the separator out with grep -v '^--$'.
Can I show context for only the first match?
Yes, combine -m 1 with the context option, grep -m 1 -A 5 pattern file. grep stops after the first matching line but still prints its trailing context.
How do I see the lines after a match in a live log?
tail -f app.log | grep --line-buffered -A 3 ERROR. --line-buffered makes grep print each line as soon as it arrives instead of waiting for its output buffer to fill.