Skip to main content

PCRE Regex in ag

Unlike standard grep, which defaults to POSIX Basic Regular Expressions (BRE) and requires flags like -E or -P for advanced syntax, ag (The Silver Searcher) uses full PCRE (Perl Compatible Regular Expressions) by default.

This is one of ag's most powerful features, allowing you to use advanced matching logic like lookaheads, lookbehinds, and named capture groups right out of the box.

Core Regex Syntax

Because ag uses PCRE natively, all standard regex operators work exactly as expected without cumbersome backslash escaping.

# Anchors: Start (^) and End ($) of line
ag "^export default" src/ # Line must start with export default
ag "\.config\.js$" file_list.txt # Line must end with .config.js

# Character Classes
ag "192\.168\.1\.[0-9]{1,3}" logs/ # Match IP subnets
ag "[[:xdigit:]]{32}" hashes.txt # Match 32-character hex strings (MD5)

# Alternation (OR logic)
ag "function (login|logout|register)" src/

Advanced: Lookarounds (Lookaheads and Lookbehinds)

Lookarounds allow you to assert that a string is preceded or followed by another pattern, without including that surrounding pattern in the actual match output. This is incredibly useful when combined with the -o (only matching) flag to extract precise data.

Positive Lookbehind (?<=pattern)

Matches only if the pattern is immediately preceded by the lookbehind pattern.

# Log: user_id=481516
# Extract just the numeric ID, ignoring the "user_id=" prefix
ag -o "(?<=user_id=)\d+" events.log

Positive Lookahead (?=pattern)

Matches only if the pattern is immediately followed by the lookahead pattern.

# Log: File processed in 42ms.
# Extract just the number, ignoring the "ms" suffix
ag -o "\d+(?=ms)" app.log

Negative Lookbehind (?<!pattern)

Matches only if the pattern is NOT preceded by the lookbehind pattern.

# Find the word "error" but ignore "no error"
ag "(?<!no )error" syslog

Named Capture Groups

If you are using ag to prototype regexes that you will later use in Python, Go, or JavaScript, you can test named capture groups directly.

# Capture the domain part of an email address
ag "(?P<username>[^@]+)@(?P<domain>[^:]+)" users.txt

[!NOTE] While ag parses named capture groups, the -o flag outputs the entire matching string, not just the captured group. If you need to extract specifically the captured group, you should pipe ag's output to sed or perl.

When to Disable Regex (-Q)

PCRE evaluation takes CPU cycles. If you are searching for a literal string that happens to contain regex metacharacters (like . or [ or (), ag will try to compile it as a regex.

Bad:

# The dots match ANY character. This matches "192x168x0x1"
ag "192.168.0.1" /var/log/

Good: Use the -Q (--literal) flag to disable PCRE and search for the exact byte sequence. This is also significantly faster.

ag -Q "192.168.0.1" /var/log/