Same pattern means different things in different tools. This is the table that resolves it.
| Tool | Default | Upgrade flag |
|---|---|---|
grep | BRE | -E for ERE, -P for PCRE |
sed | BRE | -E (or -r) for ERE |
awk | ERE-ish | gawk has more |
rg | Rust regex | no backrefs or lookaround |
perl | PCRE | |
| [[ =~ ]] in bash | ERE |
| Feature | BRE (grep/sed default) | ERE (-E, awk, bash =~) |
|---|---|---|
+, ? quantifiers | \+, \? (escaped = special) | bare + ? |
| groups | \( \) | ( ) |
| alternation | \\| | | |
{n,m} counts | \{n,m\} | {n,m} |
| backrefs in pattern | \1 | \1 for ERE search; not in rg |
Escaped-vs-bare flips between BRE and ERE: in BRE, (a) is literal parens
and \(a\) is a group; in ERE it's the opposite. When unsure, use -E.
. any char \. literal dot
* + ? 0+, 1+, 0-1 ^ $ line start/end
[abc] set [^abc] negated set
[a-z] range {n,m} counts: {3} {2,} {2,5}
x|y alternation (ERE) (x|y) group
POSIX classes (work everywhere, even BRE):
[[:digit:]] [[:alpha:]] [[:alnum:]] [[:space:]] [[:upper:]] [[:lower:]] [[:punct:]] [[:print:]] [[:blank:]] [[:xdigit:]]
GNU extras (work in GNU grep/sed both flavors): \b word boundary,
\</\> word edges, \w word char, \s whitespace, \B.
PCRE/Rust extras (grep -P, rg, perl): \d \D \s \S \w \W,
non-greedy *?, named groups (?P<n>..), lookahead (?=..) (?!..).
Note: rg's default engine supports NO lookaround/backrefs: add
rg -P to get PCRE2 when you need them.
# same task, three tools grep -E '^(Mon|Tue)' f sed -nE '/^(Mon|Tue)/p' f rg '^(Mon|Tue)' f # BRE version of the ERE "(a|b)+" grep 'x\(a\|b\)\+y' # hard to read: use -E instead # IPs: ERE grep -oE '[0-9]{1,3}(\.[0-9]{1,3}){3}' # BRE equivalent (don't do this) grep -o '[0-9]\{1,3\}\(\.[0-9]\{1,3\}\)\{3\}'
\1-\9, & = whole match.rg 'a(\d+)' -r 'num$1' uses $1.sed 's/\(.*\)/\U\1/' uppercases.|/(/{ and you did not mean regex: grep -F..* matched too much: use [^x]* or PCRE .*?.grep -z, perl -0777, or awk paragraph mode.
Line-oriented tools will not do it with $/. alone.