grep / awk / sed Text Processing Cheatsheet
TL;DR
grep defaults to basic regular expressions (-G); -E selects extended regex, -F treats patterns as fixed strings, and -P selects PCRE, which is experimental when combined with -z. grep -m NUM stops after NUM matching lines, where NUM of 0 stops immediately and -1 means infinity (the default). sed auto-prints the pattern space unless -n is given, and -i[SUFFIX] edits in place, making a backup when SUFFIX is supplied. Combining -n with p is the standard way to print only selected lines with sed.
Core Options and Defaults
| Item | Value or behavior | Caveat |
|---|---|---|
| grep default regex dialect | -G, basic regular expressions (BRE) | Applies when -E, -F, or -P is absent |
| grep extended regex | -E or --extended-regexp | Patterns interpreted as EREs |
| grep fixed strings | -F or --fixed-strings | Patterns are not treated as regex |
| grep Perl regex | -P or --perl-regexp | Experimental with -z; may warn of unimplemented features |
| grep ignore case | -i or --ignore-case | Off by default; --no-ignore-case cancels an inherited -i |
| grep invert match | -v or --invert-match | With -c, counts non-matching lines |
| grep whole word | -w or --word-regexp | Has no effect when -x is also specified |
| grep whole line | -x or --line-regexp | Equivalent to wrapping the pattern in ^ and $ |
| grep max matching lines | -m NUM, default -1 (infinity) | NUM of 0 stops at once without reading input |
| grep only matching parts | -o or --only-matching | Each matched part goes on its own output line |
| grep line prefixes | -n line number (1-based), -b byte offset (0-based), -H filename, -h suppress filename | -H is default with multiple files; -h is default with one file or stdin |
| grep file name lists | -l files with matches, -L files without matches | -l stops scanning a file at the first match |
| grep quiet and error suppression | -q writes nothing to stdout, -s suppresses errors about missing or unreadable files | -q exits immediately with zero status on any match |
| grep null separator | -Z or --null | Outputs ASCII NUL instead of the usual newline after a file name |
| sed suppress auto-print | -n, --quiet, --silent | Commonly paired with p to print only selected lines |
| sed in-place edit | -i[SUFFIX] or --in-place[=SUFFIX] | A backup is made when SUFFIX is supplied |
| sed extended regex | -E, -r, --regexp-extended | Use POSIX -E for portability |
| sed script sources | -e script, -f script-file | With neither given, the first non-option argument is the script |
| sed separate files | -s or --separate | Line numbers accumulate per file instead of across files |
| sed null data | -z or --null-data | Lines are separated by NUL characters |
| sed substitute command | s/regexp/replacement/ | In replacement, & is the whole match and \1 to \9 are subexpressions |
| sed address range | addr1,addr2 | The line matching addr1 is always accepted; a regex addr2 is not tested against that line |
| sed address negation | Append ! after the address | The command runs only when the address does not match |
Common Operations and Commands
grep: pick options by pattern type and output shape
Decide the pattern type first: use -F for literal text so regex metacharacters do not interfere, -E when you need +, ?, or {}, and -P for PCRE features. Then decide the output shape: -c for counts, -o for matched fragments, -l or -L for file names, and -q for script conditionals. -m NUM controls early stopping, while -n, -b, and -H control line prefixes.
# Recursive search in the current directory, case-insensitive, with file names and line numbers
grep -rni --include='*.conf' 'timeout' .
# Fixed-string match, only matched fragments, at most 5 lines
grep -F -o -m 5 'ERROR_CODE' app.log
# List file names with matches, NUL-separated for xargs -0
grep -lZ 'TODO' src/*.csed: substitution, deletion, and address ranges
sed makes a single pass over the input. It auto-prints the pattern space by default; -n disables that, so you must print explicitly with p. Use s/// to substitute, d to delete, c\ to replace whole lines, and y/// to transliterate. Addresses can be line numbers, first~step steps, or regexes; two addresses separated by a comma form a range, and ! negates it.
# Edit in place with a .bak backup, replacing leading foo with bar
sed -i.bak 's/^foo/bar/' config.txt
# Print only lines 10 through 20
sed -n '10,20p' input.txt
# Delete blank lines and lines matching deprecated
sed -e '/^$/d' -e '/deprecated/d' notes.mdCombining: filter with grep, then hand off to sed or awk
grep's -o emits one matched fragment per line, which works well as downstream input. sed's -s keeps line numbers separate per file, and -z handles NUL-separated data. When the upstream is a gzip stream, --label lets grep show stdin under a chosen file name.
# Extract matched fragments from a log, then strip the key prefix
grep -o 'user=[^ ]*' access.log | sed 's/^user=//'
# Label the source file name when searching a decompressed stream
gzip -cd foo.gz | grep --label=foo -H 'some pattern'FAQ
What is the difference between grep -E, -F, and -P?
-E interprets patterns as extended regular expressions (EREs), -F treats them as fixed strings rather than regexes, and -P interprets them as Perl-compatible regular expressions (PCREs). With none of these, the default is -G, basic regular expressions (BREs). -P is experimental when combined with -z and may warn about unimplemented features.
What do grep -m 0 and -m -1 do?
-m 0 makes grep stop immediately without reading input, while -m -1 is treated as infinity so grep does not stop on match count, which is also the default. With -c, the reported count does not exceed NUM; with -v, grep stops after outputting NUM non-matching lines.
Can sed -i destroy the original file?
-i[SUFFIX] edits in place, and a backup is created when SUFFIX is supplied, for example -i.bak keeps a copy of the original. Without SUFFIX, no backup is made and the original content is replaced directly.
What is special about a regex addr2 in a sed address range?
The line matching addr1 is always accepted, even if addr2 selects an earlier line, and when addr2 is a regex it is not tested against the line that addr1 matched. Appending ! after the address runs the command only when the address does not match.
Can grep -w and -x be combined?
Do not expect them to stack: -w has no effect when -x is also specified. -w requires the matching substring to be at the start of the line or preceded by a non-word constituent character, and at the end of the line or followed by a non-word constituent character; -x requires the match to equal the entire line.
Sources
- https://man7.org/linux/man-pages/man1/grep.1.html (accessed 2026-11-06)
- https://man7.org/linux/man-pages/man1/sed.1.html (accessed 2026-11-06)