Skip to content

The Silver Searcher — ag (C) ​

The tool that made "grep that respects .gitignore" a category. Its algorithms are the pre-SIMD state of the art, which makes it a useful control: everything ripgrep does faster, ag does the textbook way.

FieldValue
LanguageC
LicenseApache-2.0
Repositoryggreer/the_silver_searcher
Surveyed revisiona61f1780b64266587e7bc30f0f5f71c6cca97c0f (2.2.0-60)
CategoryUnindexed scanner
Engine classBoyer-Moore / hashed substring for literals; PCRE for regex
IndexNone
InteractiveNone

Last reviewed: August 28, 2026.


Overview ​

What it solves ​

Recursive search that skips what version control already says to skip. ag established the default that ripgrep inherited, and its literal path is a clean two-algorithm implementation with an explicit platform gate.

How it works ​

The ten dimensions ​

1. Pattern language ​

PCRE for regex; a literal fast path when the pattern has no metacharacters. Case sensitivity is a tri-state (CASE_SENSITIVE, CASE_INSENSITIVE, smart).

2. Engine architecture ​

Two literal searchers, selected by platform capability:

c
/* hash_strnstr only for little-endian platforms that allow unaligned access */

On those platforms hash_strnstr runs — a rolling-hash substring search over a precomputed table; elsewhere, boyer_moore_strnstr with alpha_skip_lookup and find_skip_lookup skip tables. [source-verified] Regex falls through to PCRE per line.

This is the pre-memmem design: skip tables rather than vectorised candidate-finding, and the field's measured answer since has been that rare-byte SIMD scanning beats classical skipping on realistic text.

3. Prefilter and literal extraction ​

None from a regex. The literal path is chosen only when the whole pattern is literal.

4. Corpus access ​

mmap by default on POSIX (MapViewOfFile on Win32), with binary files skipped before mapping when binary search is disabled — the comment notes that "if not using mmap, binary files have already been skipped", so the two paths detect at different points. [source-verified]

5. Concurrency ​

A worker pool over files, with uthash for the ignore structures.

6. Index ​

None.

7–8. Result model and Unicode ​

Matching lines in walk order; no ranking. Unicode is whatever PCRE was built with; the literal path is byte-oriented with ASCII case folding.

9–10. Interactive behaviour and evidence ​

None, and none quoted. ag's historical benchmark claims predate ripgrep and are [literature].

Strengths ​

  • Established the ignore-aware default the whole category now assumes.
  • Two literal algorithms with an explicit portability gate — unaligned access and endianness are checked rather than assumed.
  • Small and readable: the whole search core is a few hundred lines.

Weaknesses ​

  • Classical skip tables rather than vectorised search, which is where the measured gap against ripgrep comes from.
  • mmap by default, with the truncation hazard GNU grep withdrew and ripgrep made unsafe.
  • PCRE per line for regex, with no literal extraction to avoid it.
  • Maintenance has largely stopped, so it is a snapshot of 2014-era practice.

Key design decisions and trade-offs ​

DecisionRationaleTrade-off
Respect .gitignore by defaultSource trees contain build outputA correctness surface of its own (nested rules, negations)
Hash-based substring where possibleFaster than Boyer-Moore on typical textRequires little-endian + unaligned access; two code paths
mmap by defaultAvoids a copySIGBUS on concurrent truncation
PCRE per line for regexFull regex features with no engine workNo literal prefilter; every line pays the engine

Sources ​

Read at a61f1780b64266587e7bc30f0f5f71c6cca97c0f [source-verified]:

  • src/util.c — boyer_moore_strnstr, hash_strnstr
  • src/search.c — algorithm selection, mmap, binary skipping
  • src/ignore.c, src/lang.c — ignore handling and type filters