re
grep finds one thing at a time. re finds where multiple things appear together - on the same line, in the same paragraph, within N lines of each other, or anywhere in the same file. powered by RE#.
why re
# find unsafe code that unwraps within 5 lines - potential panics in unsafe blocks
# find errors mentioning timeout, but filter out debug and trace noise
# list files that use both tokio and diesel - mixed async/sync code
# find paragraphs that mention both password and plaintext - credential exposure
# search within YAML sections for entries that have both host and port
# find markdown sections that discuss both API and deprecation
with grep, each of these would require chaining multiple commands and losing file context, line numbers, and highlighting. re does it in one shot, and faster than any other tool out there.
quick start
re works similar to ripgrep for simple searches:
the difference shows up when you need more than one term.
boolean constraints
-a requires a term, -N excludes one. all terms must co-occur within the current scope (line by default).
# lines containing both "error" and "timeout"
# error but not debug - filter out noisy log lines
# lines with both literal strings (no regex interpretation)
| flag | effect | compiles to |
|---|---|---|
-a / --and |
match must also contain this pattern | &(_*pattern_*) |
-N / --not |
match must not contain this pattern | &~(_*pattern_*) |
-F / --lit |
match must contain this literal string | &(_*literal_*) |
scope
by default, all terms must appear on the same line. -d (delimiter/scope) widens the window.
| scope | flag | terms must appear within |
|---|---|---|
| line | (default) | a single line |
| paragraph | -p |
a text block separated by blank lines |
| file | -d file |
anywhere in the same file (lists filenames) |
| proximity | --near N |
N lines of each other |
| custom | -d '<delim>' |
text between occurrences of the delimiter |
# find text blocks that mention both "error" and "retry"
# list files that import both serde and async-trait
# find markdown sections discussing both API and deprecation
# find TODO and FIXME within 3 lines of each other - related work items
-p word is shorthand for --scope paragraph -a word.
the RE# pattern language
the flags are convenient shorthands, but you can also write the whole pattern as a single positional argument using boolean operators directly:
| operator | meaning | example |
|---|---|---|
& |
intersection - both sides must match | (error)&(timeout) matches lines with both |
~(...) |
complement - must not match | ~(_*debug_*) excludes lines containing debug |
_ |
wildcard - any character including newlines | _*error_* matches error anywhere in a block |
# these are equivalent:
# patterns that go beyond what flags can express:
# hex strings that contain both a digit and a letter
use \_ for a literal underscore, -R for standard regex mode, or -F for fixed strings.
try patterns interactively in the web playground.
differences from ripgrep
most ripgrep flags work the same. the key differences:
| ripgrep | re | notes |
|---|---|---|
-a processes binary files |
-a means --and (require term) |
use -uuu for binary file processing |
_ is a literal character |
_ is a wildcard |
use -R or \_ for literal underscore |
| standard regex only | adds &, ~, _ operators |
use -R to disable |
exit codes
0 match found, 1 no match, 2 error
install
cargo
prebuilt binaries
download from GitHub releases.
nix
or in a flake:
inputs.resharp.url = "github:ieviev/resharp-grep";
nix package includes shell completions.
how it works
all flags compile down to RE# patterns. for example:
compiles to:
(_*unsafe_*) & (_*unwrap_*) & ~((_*\n_*){5})
each -a term becomes an intersection, --near 5 rejects spans containing 5+ newlines, and scopes add their own boundary. because everything shares the same pattern representation, all output modes (highlighting, context, --count, --json, etc.) work uniformly.
see the RE# engine for more on the pattern language.
Have fun!