Skip to content

/commands/grep/grep-multiple-patterns

grep multiple patterns: grep -e foo -e bar, grep -E 'foo|bar'

verified onenvironmentlocal · windows 10.0.26200 arm64 · GNU bash 5.3.15 (Git Bash) · grep (GNU grep) 3.0updated
tool
grep
versions
GNU grep 3.x
os
linux, macos, windows

To print lines that match any of several patterns, pass each one with -e (grep -e error -e warning log.txt) or join them with | in an extended regular expression (grep -E 'error|warning' log.txt). Without -E, grep uses basic regular expressions where | is a literal character, so grep 'error|warning' searches for the text error|warning and usually prints nothing.

OR: any of the patterns

bash
printf 'INFO start\nWARNING disk 80%%\nERROR disk full\nINFO done\n' > app.log
echo '--- -e'
grep -e ERROR -e WARNING app.log
echo '--- -E'
grep -E 'ERROR|WARNING' app.log
echo '--- basic regex, unescaped |'
grep 'ERROR|WARNING' app.log || echo "no match (exit $?)"
echo '--- basic regex, escaped \| (GNU extension)'
grep 'ERROR\|WARNING' app.log

Output

--- -e
WARNING disk 80%
ERROR disk full
--- -E
WARNING disk 80%
ERROR disk full
--- basic regex, unescaped |
no match (exit 1)
--- basic regex, escaped \| (GNU extension)
WARNING disk 80%
ERROR disk full

Patterns from a file

-f FILE reads one pattern per line. Add -F when the patterns are fixed strings, not regular expressions (faster, and dots or brackets are not special):

bash
printf 'INFO start\nWARNING disk 80%%\nERROR disk full\nINFO done\n' > app.log
printf 'ERROR\nWARNING\n' > patterns.txt
grep -F -f patterns.txt app.log

Output

WARNING disk 80%
ERROR disk full

AND: all of the patterns

grep has no AND operator. Chain two greps, or use one regular expression for both orders:

bash
printf 'disk full on db1\ndb2 disk ok\nfull backup on db1\n' > events.txt
grep disk events.txt | grep full
echo '---'
grep -E 'disk.*full|full.*disk' events.txt

Output

disk full on db1
---
disk full on db1

Useful combinations

CommandEffect
grep -E -i 'error|warn' fEither word, any case
grep -E -w 'cat|dog' fWhole words only (no category or dogma)
grep -v -e DEBUG -e TRACE fLines matching none of the patterns
grep -E -c 'error|warn' fCount matching lines
grep -E -o 'error|warn' fPrint only the matched parts, one per line

AND in one pass with awk

When the order of the words is unknown and there are more than two, a regular expression with every permutation gets long. awk tests each condition separately on the same line:

bash
printf 'disk full on db1\ndb2 disk ok\nfull backup on db1\n' > events.txt
awk '/disk/ && /full/ && /db1/' events.txt

Output

disk full on db1

Which form to use

FormUse it when
grep -e A -e BA few patterns, each a full regex; works in GNU and BSD grep
grep -E 'A|B'Short alternations, or groups such as (dev|prod)-db
grep 'A\|B'Only with GNU grep; BSD grep on macOS does not support \| in basic regex
grep -F -f list.txtMany fixed strings, such as a list of IDs or IP addresses
grep -P 'A|B'Perl-compatible syntax such as lookarounds; GNU grep built with PCRE only

Patterns that contain regex metacharacters (., [, *) need escaping, or -F to treat them literally. An unescaped [ produces grep: Unmatched [. To search only some file types recursively with several patterns, combine these forms with grep -r --include.

egrep is an old name for grep -E; GNU grep 3.8 and later print a warning that it is obsolescent, so use grep -E in scripts.

FAQ

Why does grep 'foo|bar' print nothing?

Without -E, grep uses basic regular expressions, where | is an ordinary character. Use grep -E 'foo|bar', grep -e foo -e bar, or with GNU grep the escaped form grep 'foo\|bar'.

How do I search for a pattern that starts with a dash?

Pass it with -e, as in grep -e '-v' file, or end the options with --, as in grep -- '-v' file. Otherwise grep reads the pattern as an option.

How do I see which pattern matched on each line?

Add -o to print only the matched text, for example grep -E -o 'ERROR|WARNING' app.log | sort | uniq -c counts how often each pattern occurred.

Sources