ripgrep (rg) - Street-Level Ops¶
Real-world workflows for searching logs, configs, and code at speed.
Searching Logs for Errors¶
# Find all errors in application logs
rg "ERROR|FATAL|CRITICAL" /var/log/app/
# Show 3 lines of context around each match
rg -C 3 "OOMKilled" /var/log/syslog
# Output:
# /var/log/syslog-234: Mar 15 02:14:01 web-1 kernel: Memory cgroup out of memory
# /var/log/syslog-235: Mar 15 02:14:01 web-1 kernel: oom-kill:constraint=...
# /var/log/syslog-236: Mar 15 02:14:01 web-1 kernel: Killed process 12345 (java)
# /var/log/syslog-237: Mar 15 02:14:01 web-1 kernel: OOMKilled container api-svc
# /var/log/syslog-238: Mar 15 02:14:02 web-1 systemd: api-svc.service: main process exited
# /var/log/syslog-239: Mar 15 02:14:02 web-1 systemd: api-svc.service: restarting
# Search compressed logs (rg cannot read .gz natively — pipe through zcat)
zcat /var/log/syslog.1.gz | rg "connection refused"
# Count error occurrences per file
rg -c "ERROR" /var/log/app/
# Output:
# /var/log/app/api.log:142
# /var/log/app/worker.log:23
# /var/log/app/scheduler.log:3
Under the hood:
rgis fast because it uses memory-mapped I/O, parallel directory traversal, and the Rust regex crate with a DFA engine. On a cold cache it beatsgrep -rby 2-10x; on a warm cache the gap narrows butrgstill wins due to automatic.gitignorefiltering and smarter directory walking.
Finding Secrets and Sensitive Data¶
# Find potential hardcoded credentials
rg -i "(password|secret|api.?key|token)\s*[:=]" --type-not md
# Find AWS access keys
rg "AKIA[0-9A-Z]{16}" .
# Find private keys
rg -l "BEGIN (RSA |EC |DSA |)PRIVATE KEY"
# Find hardcoded IP addresses in YAML
rg -P '\b\d{1,3}(\.\d{1,3}){3}\b' --type yaml
# Output:
# devops/helm/values-prod.yaml: dbHost: 10.0.1.50
# devops/k8s/configmap.yaml: redis: 10.0.2.30
Code Search Patterns¶
# Find all TODO/FIXME comments
rg "TODO|FIXME|HACK|XXX" --type py --type sh
# Find function definitions in Python
rg "def \w+" --type py -o | sort | uniq -c | sort -rn | head -10
# Find all imports of a specific module
rg "^(import|from) requests" --type py
# Find where a Kubernetes resource is defined
rg "kind: Deployment" --type yaml -l
# Output:
# devops/k8s/api-deployment.yaml
# devops/k8s/worker-deployment.yaml
# devops/helm/grokdevops/templates/deployment.yaml
# Word-boundary search (match "port" but not "export" or "report")
rg -w "port" --type yaml
Infrastructure Config Search¶
# Find all Helm value references
rg "{{ \.Values\." --type yaml
# Find all Terraform resource definitions
rg "^resource " --type tf
# Find environment variable usage
rg "ENV |env:" --type docker --type yaml
# Find all listen/port configurations
rg -i "listen|port" --type conf --type yaml --type tf
# Find all references to a specific service
rg "api-service" --type yaml --type tf -l
File Filtering¶
# Search only Python files
rg -t py "import os"
# Search everything except test files
rg -g '!*test*' -g '!*spec*' "database"
# Search only Helm templates
rg -g 'templates/*.yaml' "{{ .Values"
# Exclude generated and vendor directories
rg -g '!vendor/' -g '!node_modules/' -g '!.terraform/' "config"
# Search only files tracked by git
rg --no-ignore-vcs "deprecated"
Gotcha: By default
rgrespects.gitignore,.ignore, and.rgignorefiles. This means searches insidenode_modules/,vendor/, or.terraform/return nothing unless you add--no-ignore. If a search returns no results but you know the pattern exists, try--no-ignorefirst before debugging the regex.
Replacement Preview¶
# Preview a replacement (does NOT modify files)
rg "old_function_name" --replace "new_function_name"
# Show what files would be affected
rg -l "old_api_url" --type py
# Actually perform the replacement (rg finds files, sed does the edit)
rg -l "old_api_url" --type py | xargs sed -i 's/old_api_url/new_api_url/g'
# Verify the replacement
rg "old_api_url" --type py # Should return nothing
rg "new_api_url" --type py # Should show the changes
Combining with Other Tools¶
# rg + fzf: interactive search results
rg --color=always "TODO" | fzf --ansi
# rg + jq: search JSON files then process
rg -l "error" --type json | xargs -I{} jq '.errors' {}
# rg + wc: count total matches across all files
rg -c "WARNING" /var/log/ | awk -F: '{sum+=$2} END {print sum}'
# rg + sort: find most common error messages
rg -o "Error: .*" /var/log/app/ | sort | uniq -c | sort -rn | head -10
# Output:
# 142 Error: connection timeout
# 87 Error: database unavailable
# 23 Error: invalid request format
Advanced Regex¶
# PCRE2 mode for lookaheads and backreferences
rg -P "timeout=(\d+)" --only-matching /etc/
# Multiline search (span across lines)
rg -U "def main.*\n.*return" --type py
# Match only the captured group
rg -P -o "version:\s*['\"](.+?)['\"]" --type yaml
# Case-insensitive search
rg -i "error" /var/log/syslog
# Smart case (case-insensitive unless pattern has uppercase)
rg -S "Error" # Case-sensitive because "Error" has uppercase
rg -S "error" # Case-insensitive because all lowercase
One-liner: Find the 10 most common log messages:
rg -oN "ERROR: .*" /var/log/app/ | sort | uniq -c | sort -rn | head -10— the-Nsuppresses line numbers for cleaneruniqgrouping.Remember: Smart case mnemonic: uppercase in pattern = case-sensitive, all lowercase = case-insensitive. Same as Vim's
\C/smartcasebehavior. Saves typing-ion most searches.
Configuration for DevOps¶
# Set up a global config file
export RIPGREP_CONFIG_PATH=~/.ripgreprc
cat > ~/.ripgreprc << 'EOF'
--smart-case
--glob=!.git/
--glob=!node_modules/
--glob=!.terraform/
--glob=!__pycache__/
--max-columns=200
--max-columns-preview
EOF