Dedicated Tools vs Bash
In Claude Code, the agent has access to both dedicated tools (Grep, Glob, Read, Edit, Write) and a general Bash shell. Bash can technically do everything the dedicated tools can, but at a significant token cost:
| Task | Bash command | Bash tokens | Dedicated tool | Tool tokens |
|---|---|---|---|---|
| Find login function | grep -rn "function login" . | ~2,000 (all matches) | Grep tool | ~200 (matches only) |
| List PHP files | find . -name "*.php" | head -50 | ~800 | Glob tool | ~150 |
| Read one function | cat auth.php | ~4,000 (full file) | Read with range | ~300 (lines 45-80) |
| Search for a symbol | grep -r "getUserById" | ~500 | Grep tool | ~80 |
Grep - Find Before You Read
Grep is the most powerful token-saving tool in agentic coding. Use it to locate the exact file and line before committing to reading a file. The pattern: grep first, read targeted.
# Find a function definition:
Grep: pattern="function getUserById", glob="*.php"
Result: app/models/UserModel.php:67 (tells you exactly where to read)
# Find all usages of a method:
Grep: pattern="->getUserById\(", type="php"
Result: 4 files with line numbers (read only what you need)
# Find a bug-related string:
Grep: pattern="session_regenerate_id", glob="*.php"
Result: auth/AuthController.php:89 (one file, one line)
# Find a CSS class:
Grep: pattern="\.hero-title", glob="*.css"
Result: assets/css/main.css:234 (targeted)
# Pattern: never read a file without grep-ing first
# Exception: files named in CLAUDE.md as the obvious place to look
Glob - List by Pattern
Glob finds files by name pattern and returns only paths, not content. Use it to discover file names before deciding what to read.
# Anti-pattern (Bash - returns too much):
$ find . -name "*.php" -path "*/controllers/*"
# Returns absolute paths for 40 controller files + metadata = ~500 tokens
# Better (Glob tool):
Glob: pattern="app/controllers/*.php"
# Returns just filenames sorted by modification time = ~100 tokens
# Most useful Glob patterns:
"src/**/*.ts" - all TypeScript files recursively
"app/models/*.php" - all model files
"tests/**/*Test.php" - all test files
"*.{js,ts}" - JS and TS at root
"config/*.php" - all config files
Read with Line Ranges
Once you know where a function is (from Grep), read only that range. The Read tool accepts offset (start line) and limit (number of lines).
# Full file read (anti-pattern for large files):
Read: file_path="app/models/UserModel.php"
-> 400 lines, ~3,500 tokens
# Targeted read after grep tells you login() is at line 67:
Read: file_path="app/models/UserModel.php", offset=60, limit=30
-> 30 lines (the function + context), ~280 tokens
-> 12.5x cheaper
# In Claude Code you can say:
"Read app/models/UserModel.php lines 60-90"
# The agent will use Read with the correct offset and limit
# Strategy: grep -> get line number -> read offset=(line-5) limit=40
When to Use Bash
Bash is the right choice for these operations - not for file exploration:
- Run tests -
composer test 2>&1 | tail -30(pipe to trim output) - Git operations -
git status,git diff HEAD --stat - Build / compile -
npm run build 2>&1 | tail -20 - Install packages -
composer require vendor/package - Run migrations -
php artisan migrate - Check process status -
php -v,mysql --version
Long Bash outputs are tool results that go straight into context. npm install can produce 2,000+ lines. npm install 2>&1 | tail -5 gives you just the result. composer test 2>&1 | tail -30 gives you just the test summary. Build this habit for all verbose commands.
Tool Cost Comparison
| Operation | Recommended tool | Typical tokens | Avoid |
|---|---|---|---|
| Find a function/class | Grep | 50-300 | Bash grep, cat full file |
| List files by type | Glob | 50-200 | Bash find, ls -R |
| Read a known function | Read (offset+limit) | 100-500 | Read (full file) |
| Edit a file | Edit (old_string/new_string) | ~50 | Write (full rewrite) |
| Run tests | Bash + tail | 100-500 | Bash without pipe |
| Check git changes | Bash git diff --stat | 50-200 | git diff (full patch) |
| Search all usages | Grep (files_with_matches mode) | 30-100 | Bash grep -rn |
## Tool preferences (follow these strictly)
- Use Grep tool, never `grep` or `rg` Bash commands
- Use Glob tool, never `find` or `ls -R`
- Read files with offset+limit when the target section is known
- Pipe all Bash output to `| tail -30` or `| head -20` to limit tokens
- Use Edit (old/new string) for changes, not Write (full rewrite)
- Run `composer test 2>&1 | tail -30` not `composer test` alone