Skip to main content

AND / OR Logic in Grep

grep does not have a native --and flag, and its OR syntax depends on whether you are using Basic (BRE) or Extended (ERE) Regular Expressions.

Understanding how to construct boolean logic is essential for advanced log analysis.

1. The OR Logic

To find lines that match Pattern A OR Pattern B, you have two primary options:

Option A: Extended Regular Expressions (-E)

The cleanest and most modern approach is to use the pipe operator | in an ERE block.

# Match lines containing "ERROR" or "WARN"
grep -E "ERROR|WARN" syslog

Option B: Multiple Pattern Flags (-e)

GNU grep allows you to pass multiple -e flags. grep treats these as an implicit OR. This works even in standard BRE mode without needing escaping.

# Functionally identical to the above
grep -e "ERROR" -e "WARN" syslog

2. The AND Logic

To find lines that match Pattern A AND Pattern B (regardless of order), you cannot use a simple regex. While it is theoretically possible to write a regex like A.*B|B.*A, it is unreadable and slow.

The UNIX philosophy dictates chaining tools together. The simplest and most efficient way to perform an AND operation is to pipe grep into another grep.

# Find lines that contain BOTH "ssh" AND "Failed"
grep "ssh" /var/log/auth.log | grep "Failed"

The first grep filters the stream down to only ssh lines. The second grep filters that subset down to Failed lines.

3. The NOT Logic (-v)

As covered previously, NOT is handled by the -v flag.

Combining AND, OR, NOT

You can construct highly complex filters by chaining pipelines.

Goal: Find all SSH authentications that Failed, EXCEPT those for the "root" user.

# 1. Must contain "ssh"
# 2. AND must contain "Failed"
# 3. AND NOT contain "root"
grep "ssh" /var/log/auth.log | grep "Failed" | grep -v "root"

4. Complex Regex AND (Order Dependent)

If you need to match Pattern A AND Pattern B, but you know that A will always appear before B on the line, you can use the regex wildcard .*.

# Matches "user admin triggered failure"
# Will NOT match "failure triggered by admin"
grep -E "admin.*failure" app.log

This is computationally faster than piping, but less flexible as it strictly enforces the order of the strings.