Building with AI – A Developer's Diary

grep — The Command I Wish Someone Had Shown Me First

A self-taught developer's honest account of discovering grep late, using it badly, and finally understanding why it's the one tool that changes how you read a codebase.

NoCo Interactive • Terminal · Unix tools • 6–8 minute read •

I learned to code before Stack Overflow existed. Before tutorial sites, before YouTube walkthroughs, before you could paste an error message into a search box and get an answer in thirty seconds. You learned from whoever sat near you, from books you could afford, and from making the same mistake enough times that you finally stopped making it. There was no fast path. Most of the time, there was no path at all—just the source code and a lot of patience.

Which is why it took me an embarrassingly long time to really learn grep.

What I actually did instead

For years I searched for things the slow way. I'd open files one by one. I'd scan with my eyes. I'd remember vaguely that a function was "somewhere in the utils folder" and just start opening files until I found it. If a project got too big, I'd lean on my IDE's search functionality.

I knew grep existed. I'd even used it. But I used it the way you use a tool you learned from watching someone else for thirty seconds—I knew the shape of it without understanding what it was actually doing.

Shell
grep "something" file.txt

That was my entire mental model. One pattern, one file. If I needed to look in multiple files I'd reach for a text editor's find-in-project instead. It worked well enough that I never felt the gap—until the projects got large enough, or I was on a remote server with no GUI, or I was looking at a codebase that wasn't mine.

The command that changed my mental model

The shift happened when someone showed me -r. Recursive grep. Search an entire directory tree with one command.

Shell
grep -r "functionName" ./src

That was it. That was the whole thing. But it opened something up. The question stopped being "which file is this in?" and started being "where is this used across the entire project?" Those are different questions with different answers, and the second one is almost always the one that matters.

Then came -n, which adds line numbers to every match. Then -l, which skips the matched lines entirely and just gives you file names—useful when you want to know which files to open, not read every match inline. Then -i for case-insensitive matching, which sounds minor until you're searching a codebase where half the team capitalizes things differently.

Shell
grep -rn "TODO" ./app           # every TODO with file and line number
grep -rl "deprecated" ./lib     # just the files containing "deprecated"
grep -ri "config" ./src         # case-insensitive across all of src

Each of these I'd learned to do some other way—slower, with more steps. The flags didn't add new capabilities so much as they collapsed workflows I'd been doing manually into single commands I could run in two seconds.

The part nobody tells you about when you're self-taught

When you learn without a mentor, you fill in the gaps with workarounds. The workarounds work, so you keep them. Nobody tells you there's a better way because nobody's watching you work—they only see the output. You ship the feature, the output looks fine, and the inefficiency stays invisible.

That's what happened with grep. My workarounds for finding things worked well enough that I never felt the cost. The cost was real—it showed up as extra minutes every day, as hesitation before exploring unfamiliar code, as a reluctance to jump into legacy projects I didn't already know—but it was diffuse enough that I never connected it to the underlying cause.

Learning the flags properly wasn't just about typing fewer characters. It changed how willing I was to go looking. When you can search a codebase in two seconds, you search more. When you search more, you understand more. When you understand more, you move faster. The compounding is real, and it starts with a tool most people think they already know.

The flags worth actually memorizing

Not all of them. There are dozens of grep flags and most of them solve problems you'll encounter once a year. These are the ones that come up every week:

  • -r — recursive; search all files in a directory tree
  • -n — line numbers in output
  • -i — case-insensitive matching
  • -l — filenames only; skip printing matched lines
  • -v — invert match; show lines that do not match
  • -c — count of matching lines per file
  • -A, -B, -C — lines of context after, before, or around a match
  • --include — restrict to files matching a glob (e.g. --include="*.php")
  • -E — extended regex; use +, ?, | without escaping them

The context flags are the ones that turn grep from a search tool into a reading tool. -C 3 means "show 3 lines above and below each match." You stop jumping to the file and start reading the code inline, right in the terminal.

Shell
grep -rn "createSession" ./app --include="*.php" -C 2

That command finds every place createSession is called in PHP files, with two lines of context around each match. You can read the surrounding logic without opening a single file. On a large codebase, that's not a small thing.

What the reference PDF covers

The sheet is organized the way I wish someone had handed it to me: the flags you'll use daily in one section, pattern syntax in another, and practical combinations—the multi-flag commands you build up over time—in a third. It's sized to print on one page, or to keep open on a second monitor while you practice.

The goal isn't memorization. The goal is to run a command, look something up, run it again, and repeat that often enough that the flags stop being things you look up and start being things you reach for without thinking.

The tools that changed how I work were almost never the sophisticated ones. They were the simple ones I'd been underusing for years—the ones where learning ten more minutes of depth paid off every single day after.

← Back to Building with AI – A Developer's Diary