Patterns in grep: BRE and ERE

grep, sed & awk · Essentials · 12 min

Real searches are rarely literal strings; a few regex pieces turn grep into a precise tool.

grep patterns are regular expressions. The pieces you need first:

  • . any character; [abc] one of a set; [^abc] anything but; [0-9], or the portable [[:digit:]], [[:space:]], [[:alpha:]].
  • ^ start of line, $ end of line: ^# finds comment lines, ^$ empty ones.
  • * repeats the previous item zero or more times.

grep has two dialects. Basic regular expressions (BRE, the default) treat + ? | ( ) { } as ordinary characters; you must write \+, \|, \(...\) to get their special meaning (a GNU extension for \+ \? \|). Extended regular expressions (ERE, grep -E, formerly egrep) make them special without backslashes:

  • + one or more, ? optional, {2,4} between two and four.
  • a|b alternation, (...) grouping.

Use -E whenever your pattern has alternation or repetition; it is far easier to read. -o prints only the matched part instead of the whole line, which is handy for extracting values.

grep never supports \d in BRE or ERE in a portable way; use [0-9] or [[:digit:]]. For Perl-style syntax (\d, lookarounds) GNU grep has -P, covered later.

Example

printf 'id=42 ok\nid=7 FAIL\n# comment\n\nid=1234 ok\n' > data.txt

grep '^#' data.txt                         # # comment
grep -c '^$' data.txt                      # 1  (empty lines)
grep 'id=[0-9][0-9]* ok$' data.txt         # id=42 ok / id=1234 ok   (BRE)
grep -E 'id=[0-9]+ (ok|FAIL)' data.txt     # every id line            (ERE)
grep -E 'id=[0-9]{3,}' data.txt            # id=1234 ok
grep -oE '[0-9]+' data.txt                 # 42 / 7 / 1234, one per line

grep 'ok|FAIL' data.txt                    # nothing: | is literal in BRE
grep 'ok\|FAIL' data.txt                   # works in GNU BRE, but prefer -E

Remember

  • ^ and $ anchor to line start and end
  • Use grep -E for + ? | ( ) { } without backslashes
  • -o prints just the matched text; use [0-9] instead of \d

Watch out for

  • Writing grep 'a|b' and getting no matches: alternation needs -E (or \| in GNU BRE).

Check yourself

  1. Which command prints lines that consist only of digits?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: www.gnu.org/software/grep/manual/grep.html#Regular-Expressions