grep -rn Changed How I Debug. I Use It Before I Open a Single File.

grep -rn Changed How I Debug. I Use It Before I Open a Single File.

Leader 1 5 42
calendar_todayschedule3 min read

I used to open files to search for things.

A config had the wrong database host somewhere. I knew it was in one of the files in /etc/nginx/ but I didn't know which one. So I opened nginx.conf. Searched. Not there. Opened sites-available/default. Searched. Not there either. Opened three more files. Found it in the fourth one.

That took about 4 minutes. The grep command that does the same thing takes less than a second:

grep -rn "db.old-host.com" /etc/nginx/

Every file. Every subdirectory. Exact filename. Exact line number. Done.

I genuinely don't understand why it took me so long to make this my default workflow instead of manually opening files like it's 2004.


The Script

#!/bin/bash
# Search files for text — grep reference

KEYWORD="TODO"          # ← what to search for
SEARCH_DIR="$HOME"      # ← where to search
FILE_TYPE="*.txt"       # ← file types to include

echo "Searching for '$KEYWORD' in $SEARCH_DIR..."
echo "────────────────────────────────────────"

grep -rn "$KEYWORD" "$SEARCH_DIR" \
  --include="$FILE_TYPE" \
  --color=auto

COUNT=$(grep -rc "$KEYWORD" "$SEARCH_DIR" \
  --include="$FILE_TYPE" 2>/dev/null \
  | grep -v ":0$" | wc -l)

echo "────────────────────────────────────────"
echo "Found in $COUNT file(s)"

But honestly, you'll use the raw command more than the script. The script is a reference. The command is the weapon.


The Flags That Actually Matter

grep -r — recursive. Searches every file in the directory and all subdirectories. Without this, grep only searches the one file you hand it.

grep -n — line numbers. Instead of just showing the matching line, it shows filename:42: the matching line. Now you know exactly where to look.

grep -rn — both together. This is the one I type the most. grep -rn "ERROR" /var/log/ and I immediately see every error across every log file with the exact line number.

*`--include=".py"** — filter by file type. If you only want to search Python files, or only .conf files, or only .html` files, this prevents grep from wasting time on binary files and irrelevant formats.

--color=auto — highlights the matched keyword in the output. When you're scanning 50 results, the color makes the keyword jump out instantly.

-i — case-insensitive. grep -rni "error" /var/log/ catches "Error", "ERROR", "error", and any other capitalization.

-l — filenames only. When you don't need to see the matching lines, just which files contain the keyword. grep -rl "TODO" ./src/ gives you a clean list of files.

-c — count matches per file. grep -rc "TODO" ./src/ shows filename:3 meaning 3 matches in that file.


The Combinations I Use Every Week

Find every TODO in a project:

grep -rn "TODO" ./src/ --include="*.js"

Find which config file has a specific setting:

grep -rn "max_connections" /etc/

Find a function definition across a codebase:

grep -rn "def process_order" ./app/ --include="*.py"

Find IP addresses in log files:

grep -rn "192.168" /var/log/ --include="*.log"

Find files that contain a string but don't care about the matching lines:

grep -rl "database_url" ./config/

Your editor's search (Ctrl+Shift+F in VS Code, Cmd+Shift+F on Mac) does basically the same thing — but only for files that are open in your project.

grep works on any directory on any machine, including servers where you only have SSH access and no editor at all. When you're debugging a production issue over SSH at 11 PM, grep -rn is the fastest path from "I know the error is in here somewhere" to the exact line.

It's also faster on large directories because it doesn't need to index anything first. It just reads files sequentially and matches the pattern.


One Gotcha Worth Knowing

grep on binary files produces garbage output. If you're searching a directory that contains images, compiled files, or databases, add --binary-files=without-match to skip them:

grep -rn "search_term" /some/dir/ --binary-files=without-match

Or use --include to limit to specific text file types, which solves the same problem more precisely.


Full script, flag cheat sheet, and more combinations:

bashsnippets.xyz/snippets/search-files-for-text-grep.html

If you want to quickly look up the flags without reading a man page, I keep a reference table on the snippet page with every flag I've actually used in production.

Part 3 of 7 in Bash Snippets Tools
🔥 Join developers growing publicly
Share your knowledge, build in public, and grow your developer presence with a global community.

More Posts

How I Built a React Portfolio in 7 Days That Landed ₹1.2L in Freelance Work

Dharanidharan - Feb 9

I’m a Senior Dev and I’ve Forgotten How to Think Without a Prompt

Karol Modelskiverified - Mar 19

My Nginx Died at 2 AM and Nobody Noticed for 6 Hours. Now I Have a Watchdog Script

BashSnippets - May 21

TypeScript Complexity Has Finally Reached the Point of Total Absurdity

Karol Modelskiverified - Apr 23

Sovereign Intelligence: The Complete 25,000 Word Blueprint (Download)

Pocket Portfolio - Apr 1
chevron_left
2.7k Points48 Badges
North Americabashsnippets.xyz
32Posts
26Comments
3Connections
Linux user who got tired of Googling the same bash commands every time I sat down at a terminal. Sta... Show more

Related Jobs

View all jobs →

Commenters (This Week)

1 comment
1 comment

Contribute meaningful comments to climb the leaderboard and earn badges!