grrep /[ɡɜːr]ep/ Global Rapid Regular Expression Print
A small and fast recursive grep written in Go. Install with go github.com/bep/grrep@latest.
usage: grrep [-q] [-F] [-i] [-w] [-v] [-d N] [--no-ignore] PATTERN [PATH]
Flags:
-F treat PATTERN as a fixed string, not a regex
-i case-insensitive match
-d, --max-depth=N search at most N directory levels (1 = root only, 0 = nothing)
--no-ignore do not respect .gitignore/.ignore files
-q quiet: suppress match output
-v select non-matching lines
-w match only at word boundaries
I needed a search tool that plays nicely with gitjoin — the joined-in subrepositories are listed as .gitignore entries in the host repo, and a normal grep would refuse to descend into them. grrep skips the gitjoin-managed block when reading .gitignore, so the joined repos remain searchable as one tree.
The other motivation was curiosity: how far Go and the standard library can take a tool like this before reaching for non-stdlib regex/SIMD or unsafe code.
- Honors
.gitignoreand.ignorefiles in the search tree. - Does not honor
~/.gitignore_global. - Skips the
# Managed by gitjoin … # End gitjoin managed sectionblock when reading any.gitignore. - Skips hidden files and directories.
- Skips files whose first 8 KiB contain a NUL byte (binary heuristic).
Similar shape to the first table in ripgrep's "Quick examples comparing tools", on a MacBook Pro M1 (32 GB) against the current torvalds/linux after make defconfig && make -j8.
Tree:
| metric | count |
|---|---|
| files (excluding hidden) | 118,270 |
files visible after .gitignore |
93,593 |
files filtered by .gitignore |
24,677 |
Pattern: [A-Z]+_SUSPEND matched as a whole word (-w). All three tools find the same 575 matches.
| tool | median wall (n=7) |
|---|---|
| ugrep | 1.184s |
| grrep | 1.664s |
| ripgrep | 3.467s |
Reproduce with bash bench.sh.
The Linux source contains paths that collide on a case-insensitive filesystem (e.g. Documentation/Kbuild and Documentation/kbuild/). Clone into a case-sensitive volume, then build inside a Linux container:
diskutil list # find the APFS container (often disk3)
diskutil apfs addVolume disk3 'Case-sensitive APFS' LinuxBench
cd /Volumes/LinuxBench
git clone --depth=1 https://github.com/torvalds/linux.git
docker run --rm \
-v /Volumes/LinuxBench/linux:/src -w /src \
ubuntu:24.04 \
bash -c '
apt-get update -qq
DEBIAN_FRONTEND=noninteractive apt-get install -yqq --no-install-recommends \
build-essential bc bison flex libssl-dev libelf-dev cpio kmod \
python3 rsync dwarves
make defconfig && make -j8
'The build creates the ~25 K .o / .cmd / etc. artifacts that make the .gitignore path matter.