Search & Regex
grep, ripgrep (rg), find, sed, and awk - the Linux text search toolkit Python developers use to grep logs, locate files, and one-shot transform configs on servers.
Recipe
rg "TaxCalculator" src/
rg -n "raise_for_status" --type py
find /var/log/myapp -name "*.log" -mtime +7
grep -E "ERROR|CRITICAL" /var/log/myapp/app.log | tail -50When to reach for this:
- Find symbol definition across Python monorepo
- Search production logs for trace id
- Locate large or old files before cleanup
- Quick field extraction from CSV/log lines
Working Example
# Find all TODO(FIXME) in Python sources
rg -n "TODO|FIXME" -g "*.py" src/ tests/
# Find config referencing old Redis host
rg -l "redis://legacy" --glob "!uv.lock"
# Logs: errors in last hour with request id
journalctl -u billing-api --since "1 hour ago" | rg "request_id=550e8400"
# Delete stale rotated logs older than 14 days (dry run first)
find /var/log/billing-api -name "*.log.*" -mtime +14 -printWhat this demonstrates:
rgtype and glob filters reduce noise-llists files only for bulk replace planningjournalctlpiped torgfor structured grepfind -printbefore-deletesafety
Deep Dive
How It Works
- grep - Line-oriented regex match;
-rrecursive (slow on big trees). - ripgrep - Parallel, gitignore-aware, default for code search.
- find - Directory traversal by name, time, size, type.
- sed - Stream editor for substitute/delete lines.
- awk - Column-oriented processing.
Tool Picker
| Task | Tool |
|---|---|
| Code symbol search | rg pattern src/ |
| JSON logs | jq (preferred) or rg on key |
| File by name | find . -name '*.py' |
| In-place replace | sed -i.bak with backup |
| CSV 3rd column | awk -F, '{print $3}' |
Python Notes
# Equivalent to rg for one file with line numbers
grep -n "def main" src/app/cli.py
# Find empty __init__.py markers
find src -name "__init__.py" -emptyGotchas
grep -rfrom / - IO storm and permission errors. Fix: always start from project or/var/log/app.- sed -i without backup on prod - Broken config unrecoverable. Fix:
-i.bakor edit locally + deploy. - Regex greediness - Wrong sed matches multiline config. Fix: test on copy; prefer
rglocate + manual edit for critical files. - Ignoring binary matches - grep prints "Binary file matches". Fix:
rgorgrep -I. - Locale breaks character classes - Unexpected sort/match. Fix:
LC_ALL=Cfor ASCII logs. - Awk on JSON - Fragile vs nested objects. Fix:
jqfor JSON logs.
Alternatives
| Alternative | Use When | Don't Use When |
|---|---|---|
| IDE search | Local refactor | SSH-only prod logs |
git grep | Tracked files only | Generated or log files |
ag / ack | Legacy environments | rg available |
| Python script | Complex parsing | One-liner faster in shell |
FAQs
rg or git grep?
rg for speed and ignore rules; git grep when searching only committed snapshots at specific revision.
Case insensitive search?
rg -i pattern or grep -i.
Multiline regex?
rg -U multiline mode for cross-line patterns - use sparingly.
find mtime vs atime?
mtime file content change; atime access (often disabled on servers for performance).
sed GNU vs BSD on Mac?
macOS sed requires backup extension sed -i '' - test on target OS.
Exclude venv from grep?
rg auto-ignores; for grep use --exclude-dir=.venv.
Count matches?
rg -c pattern per file or rg pattern | wc -l.
Search compressed logs?
zgrep / zcat file.gz | rg pattern.
Parallel find delete?
Avoid find -delete at scale without -print dry run first.
Regex in Python vs shell?
Prefer Python re in application code; shell regex for operator one-offs only.
Related
- re - Regular Expressions - Python regex
- Pipes & Text Processing - composing tools
- Parsing Logs and Text - log pipelines
- Shell Productivity - aliases for search
Stack versions: This page was written for Python 3.14.0 (stable 3.14, maintenance 3.13), FastAPI 0.115+, Django 5.2, Flask 3.1, Pydantic 2, PyTorch 2.6+, pandas 2.2+, Polars 1.x, ruff 0.9+, and uv 0.6+.