How to Use ripgrep (rg) Instead of grep
ripgrep (rg) is a fast, Rust-powered grep replacement with gitignore support built in. Learn installation, regex syntax, and the most useful flags.
Before you start
- ▸A terminal with bash or zsh
- ▸sudo or root access to install packages
- ▸Basic familiarity with using grep or searching files from the command line
ripgrep (rg) is a line-oriented search tool that recursively searches directories for a regex pattern. It is faster than grep in almost every real-world benchmark, respects .gitignore rules by default, and has sensible defaults that cut down on flag-typing. If you spend any time searching codebases or log files from the command line, switching to rg is one of the easiest quality-of-life upgrades you can make.
Why ripgrep Is Faster
ripgrep is written in Rust and uses the regex crate, which compiles patterns to finite automata and avoids backtracking on most inputs. Beyond the regex engine, three things explain the speed advantage over GNU grep:
- Automatic parallelism: directory traversal runs across multiple threads by default.
- Smart file skipping: hidden files, binary files, and anything matched by a
.gitignore,.ignore, or.rgignorefile are skipped without you asking. - Memory-mapped I/O: for large files,
rgcan read directly from mapped memory rather than buffering through the kernel.
On a typical Node.js or Python project directory, rg is 5–10× faster than grep -r because it never enters node_modules or .git — those are covered by .gitignore.
Installation
Debian / Ubuntu
sudo apt update && sudo apt install ripgrep
Fedora / RHEL 9+ / Rocky Linux
sudo dnf install ripgrep
On RHEL 8 and older Rocky 8, enable the EPEL repository first: sudo dnf install epel-release.
Arch Linux
sudo pacman -S ripgrep
Verify the install
rg --version
Output will look similar to: ripgrep 14.1.0 (rev ...). The exact version varies by distro.
Basic Search Syntax
The simplest form mirrors grep: a pattern and an optional path. Without a path, rg searches the current directory recursively.
# Search current directory recursively
rg 'TODO'
# Search a specific file
rg 'error' /var/log/syslog
# Search a specific directory
rg 'def main' ~/projects/myapp
Output includes the filename, line number, and a highlighted match. Colours are on by default when writing to a terminal.
Regex Syntax
ripgrep uses Rust regex syntax, which is close to PCRE but with some differences: lookaheads and backreferences are not supported by default. For most searches this never matters. Use -P (PCRE2 mode) if you need them — provided rg was compiled with PCRE2 support, which most distro packages include.
Common patterns
# Case-insensitive match
rg -i 'warning'
# Match whole words only
rg -w 'log'
# Fixed string (no regex interpretation — faster for literals)
rg -F 'user.name'
# Extended regex — already the default, but explicit
rg -e 'foo|bar'
# PCRE2 for lookahead
rg -P 'foo(?=bar)'
Anchors and character classes
# Lines starting with a hash (comments)
rg '^#' config.ini
# IP-address-like pattern
rg '\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b' access.log
# Match lines that end with a semicolon
rg ';$' src/main.c
gitignore Support and Controlling What Gets Searched
By default rg reads and respects these ignore files in order: .gitignore, .git/info/exclude, a global gitignore, .ignore, and .rgignore. This is the single biggest practical advantage over plain grep -r.
# Override gitignore — search everything including ignored paths
rg --no-ignore 'secret'
# Include hidden files and directories (e.g. dotfiles)
rg --hidden 'alias'
# Both: search absolutely everything
rg --no-ignore --hidden 'password'
# Add your own ignore file per-project
echo 'dist/' >> .rgignore
Useful Flags
Filtering by file type
ripgrep has a built-in type system. Use --type (-t) to restrict searches to known file extensions, or --type-not (-T) to exclude them.
# Only Python files
rg -t py 'import os'
# Exclude test files (JavaScript)
rg -T js 'console.log'
# List all known types
rg --type-list
Context lines
# 3 lines before and after each match
rg -C 3 'panic'
# Only lines before
rg -B 2 'ERROR'
# Only lines after
rg -A 5 'BEGIN CERTIFICATE'
Counting, filenames, and line numbers
# Count matches per file
rg -c 'TODO'
# Print only filenames that contain a match
rg -l 'FIXME'
# Suppress line numbers (they're on by default with color output)
rg --no-line-number 'debug'
Multiline mode
By default rg matches line by line. Enable multiline mode with -U to let . match newlines.
rg -U 'start.*?end' --multiline-dotall src/
Replace (non-destructive preview)
rg does not edit files in place, but the -r flag prints what a substitution would look like — useful before piping into sed.
# Preview replacement output
rg 'foo' -r 'bar' src/config.py
Output formatting and piping
# Null-delimited filenames for xargs
rg -l0 'TODO' | xargs -0 vim
# JSON output for scripting
rg --json 'error' app.log | jq '.data.lines.text'
Practical Recipes
# Find all functions named 'handle_*' across a Go project
rg 'func handle_\w+' --type go
# Search compressed logs (requires rg compiled with the 'search-zip' feature)
rg -z 'Out of memory' /var/log/
# Find TODO comments with the author name that follows
rg 'TODO\(\w+\)'
# Search only files modified in the last day (combine with find)
find . -mtime -1 | xargs rg 'migration'
Verification
Clone a small public repo (or use any local project) and compare timing against GNU grep to confirm rg is working correctly and faster:
time grep -r 'TODO' ~/projects/myapp --include='*.py' > /dev/null
time rg 'TODO' -t py ~/projects/myapp > /dev/null
Both should return the same results. rg should be measurably faster on any directory with more than a few hundred files.
Troubleshooting
rg skips files you expect to be searched
Run with --debug to see exactly which files are being skipped and why:
rg --debug 'pattern' 2>&1 | grep 'ignore\|skip'
The most common cause is an overly broad .gitignore entry. Use --no-ignore to bypass all ignore files as a diagnostic step.
No matches but you are sure the text is there
Check whether the file is binary. rg skips binary files by default. Add -a (--text) to force text mode:
rg -a 'pattern' suspicious_file
Pattern works in grep but not rg
GNU grep defaults to BRE/ERE; rg uses Rust regex syntax. Character class shortcuts like \w work in both, but POSIX classes like [:alpha:] need a different form. Try -P for PCRE2 mode if you are porting a complex grep command.
Frequently asked questions
- Does ripgrep support all the same regex features as grep?
- Not quite. ripgrep uses Rust regex syntax, which does not support backreferences or lookaheads by default. Add -P to enable PCRE2 mode, which supports those features, as long as your installed rg binary was compiled with PCRE2 support (most distro packages are).
- Why is rg not searching inside node_modules or .git?
- Those directories are typically listed in .gitignore, and rg respects that file by default. This is intentional and usually desirable. Use --no-ignore to force rg to search them anyway.
- Can ripgrep search inside compressed or binary files?
- Binary files are skipped by default; add -a (--text) to treat them as text. Compressed file searching (gzip, etc.) is supported with the -z flag if rg was compiled with that feature enabled.
- Can I use rg as a drop-in replacement for grep in shell scripts?
- Mostly yes, but not perfectly. Exit codes are compatible (0 for match found, 1 for no match), but flag names differ — for example, rg uses --count not -c for counting, wait, actually -c works too. Test your scripts carefully; complex grep invocations may need adjustments.
- How do I make ripgrep search hidden dotfiles by default?
- Add --hidden to your rg invocation, or add it permanently by putting hidden = true in ~/.config/ripgrep/config (create the file if it doesn't exist; set the environment variable RIPGREP_CONFIG_PATH to point to it if needed).
Related guides
Bash Arrays and Associative Arrays
Master bash indexed and associative arrays: declaration, element access, looping, mapfile, namerefs, and practical patterns for real scripting work.
Bash Functions and Variable Scoping
Master Bash function scoping with local variables, source-based libraries, correct use of return codes, and array passing techniques including namerefs.
Bash Loops: for, while and until
Learn all three Bash loop types — for, while, and until — with practical, copy-paste examples covering file iteration, counting, polling, and safe line reading.
Bash Scripting for Beginners
Learn Bash scripting from scratch: shebang lines, variables, conditionals, loops, and arguments, plus a real backup script to tie it all together.