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|balternation,(...)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 -ERemember
- ^ 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).