Step 20. Searching (grep/find) — Finding Two Needles in a Haystack

Step 20. Searching (grep/find) — Finding Two Needles in a Haystack

Level 0 — Understanding Computer Operation and Structure | Difficulty ★★★☆☆ | Estimated time: 3 hours

Prerequisites: Step 19 complete. Work in the Ubuntu terminal inside your virtual machine.

  • What you need: the Ubuntu virtual machine, a terminal. Every command from Steps 18–19 becomes an ingredient today.
  • Caution: today’s exercise is reading and searching only, so it’s 100% safe. This chapter produces lots of output, but don’t be intimidated — after learning how a lot comes out, you’ll also learn how to narrow it down.
  • Hands-on note: the outputs in this chapter are real results run on Ubuntu 24.04. The verification was done with the administrator (root) account, so paths show /root, and the permission-error experiment (Section 3-2) was additionally run with an unprivileged account to reproduce an ordinary user’s situation. On your VM, home appears as /home/username.

An investigator at a crime scene asks two kinds of questions: "find the person named so-and-so" (search by identity) and "find the person who said such-and-such" (search by content). Filesystems are the same. Today’s two protagonists — grep searches by content, find searches by name and conditions. Remember digging through logs with Select-String in Step 4? grep is its Linux ancestor, and a command security analysts around the world type hundreds of times a day.


1. Learning Objectives

By the end of this chapter, you will be able to:

  • Explain the difference in roles between grep (content search) and find (name/condition search)
  • Search the contents of entire folders with grep -r, -i, and -n
  • Search by name, size, and modification time with find
  • Decode each part of 2>/dev/null using pipe knowledge, and use it
  • Connect find and grep with pipes to conduct "narrow down, then narrow again" investigations

2. Background Knowledge — Today’s Tools and Concepts

Today’s Tools at a Glance

Category Details
Language/Environment Ubuntu Linux terminal (bash)
Today’s commands grep -r/-i/-n (content search), find -name/-size/-mtime (condition search), 2>/dev/null (discard errors), history | grep (find past commands)
Concepts needed wildcards (*), standard stream numbers (Step 19), /dev/null, chained pipes

2-1. grep — A Magnifying Glass Inside Documents

grep‘s basic form: grep "word" file. It shows the lines in that file containing "word."

Three key options:

Option Meaning
-r search whole folders (recursive — all subfolders)
-i ignore case (Password or PASSWORD alike)
-n show line numbers too

The name’s origin is fun — it comes from the first letters of an ancient Unix text-editor command: "globally search a regular expression and print." You’ll formally learn regular expressions in Level 1; today, plain literal search is already plenty powerful.

2-2. find — The Condition Investigator

find‘s basic form: find where -condition value. Get a feel from examples:

Command Meaning
find ~ -name "*.txt" under my home, things whose names end in .txt
find ~ -size +10M things bigger than 10 MB (+ means "over," – means "under")
find ~ -mtime -1 things modified within the last day (-1)

find’s charm from a security perspective: searching for "recently changed files" is a breach-investigation classic — the technique for finding which files on a system were touched right after an attack. Searching for "suspiciously large files" is the technique for finding traces of data exfiltration.

2-3. Decoding 2>/dev/null — Today’s Magic Spell

When you search the entire system, folders you don’t have read permission for spew piles of "Permission denied" errors, and the results get buried under them. The stock phrase for that situation is 2>/dev/null. Let’s decode it with Step 19’s knowledge:

  • 2 — the error pipe (stderr’s number)
  • > — change direction (redirection)
  • /dev/null — Linux’s trash-can file (whatever goes in vanishes)

Put together: "send errors to the trash and show me only the normal results." /dev/null is also a fun example of the "everything is a file" philosophy — even the trash can is a file.

2-4. When to Use Which

Situation Tool
You know the filename or part of it find
You know part of the file’s content grep
Searching by attributes like time or size find
You want the lines in a log containing a certain word grep

In the field, you chain the two: narrow down candidate files with find, then search their contents with grep.


3. Follow Along

3-1. grep Basics — Searching Within One File

grep "root" /etc/passwd
root:x:0:0:root:/root:/bin/bash

(Verified 2026-09-09.)

How to read the output: the lines in /etc/passwd containing "root." It’s an accounts file, so of course the root line shows up. Now a case experiment:

grep -i "ROOT" /etc/passwd
root:x:0:0:root:/root:/bin/bash

(Verified 2026-09-09.)

Same result. That’s because -i ignored case. When you’re not sure about case in a search, adding -i is the safe move.

3-2. grep -r — Searching Whole Folders (and Permission Errors)

grep -r "password" /etc 2>/dev/null | head -6
/etc/default/useradd:# The number of days after a password expires until the account
/etc/ssl/openssl.cnf:# input_password = secret
/etc/ssl/openssl.cnf:# output_password = secret
/etc/ssl/openssl.cnf:challengePassword		= A challenge password
/etc/pam.d/su:# This allows root to su without passwords (normal operation)
/etc/pam.d/su:# su without a password.

(Verified 2026-09-09. Results differ by environment.)

How to read the output: the format is filename:content — which file and which line comes first. It searched all of /etc for lines containing "password."

But what happens if you remove 2>/dev/null and run it as a regular user? We verified (running with an unprivileged account):

grep: /etc/shadow-: Permission denied
grep: /etc/sudoers: Permission denied
grep: /etc/gshadow: Permission denied
grep: /etc/landscape/client.conf: Permission denied

(Verified 2026-09-09 — the actual error messages from running grep -r "password" /etc as a non-root account. Just run it as your own VM account and you can see this sight yourself.)

Thanks to 2>/dev/null, not one of these errors appeared in Section 3-2’s main text. Run it without → a pile of errors; run it with → results only. That contrast must be clear before it becomes a habit.

Why do it: this one line is "find password-related settings somewhere in the config files." In breach investigations, "search everything for a string the attacker left behind" uses exactly this form.

3-3. find Basics — Searching by Name

find /etc -name "*.conf" 2>/dev/null | head
/etc/pam.conf
/etc/modules-load.d/modules.conf
/etc/PackageKit/PackageKit.conf
/etc/PackageKit/Vendor.conf
/etc/landscape/client.conf
/etc/rsyslog.conf

(Verified 2026-09-09. head defaults to 10 lines — in verification only 6 lines came out before the list was exhausted; your environment may show more.)

How to read it: files under /etc whose names end in .conf. The * in *.conf is a wildcard meaning "any characters" (the one you met in Step 2 — Linux has it too). The trailing | head means "just the beginning" — the Step 19 technique for peeking when results are plentiful.

What are .conf files: short for configuration — most Linux configuration files carry this extension and gather in /etc. Unlike Windows, which uses a dedicated DB called the registry (Step 11), Linux settings are text that’s easy to find, read, and back up.

3-4. find Attribute Search — Size and Time

find ~ -mtime -1 2>/dev/null | head
/root
/root/stream-lab
/root/stream-lab/filelist.txt
/root/stream-lab/a.txt
/root/stream-lab/live.log
/root/practice
/root/practice/file2.txt
...

(Verified 2026-09-09 — the files made in Steps 18–19 come out in a row. Your results will likewise be filled with what you made today.)

Files modified within the last day. Try a size condition too:

find ~ -size +1M 2>/dev/null

Files in my home bigger than 1 MB. (On a practice VM there may be none — if so, lower the bar to -size +100k. In the verification environment, two cache files were caught.)

Reading with an investigator’s eyes: "the list of files that changed on this computer today" — this is the Linux version of timeline investigation. Same mindset as Step 12’s event-log timeline, different tool.

3-5. Searching history — Finding in Your Own Past

history | grep find
    1  find /etc -name "*.conf" 2>/dev/null | head
    3  find ~ -mtime -1

(Verified 2026-09-09 — only the find commands were picked out. Your output will show the exact order and numbers you typed today.)

How to read it: the command history you saw in Step 18 was piped into grep, picking out only "commands that used find." This is the best field tip for "what was that command again?" Don’t retype long commands — find them like this.

Make a prediction: what will grep -r "root" /etc 2>/dev/null | wc -l print? (Answer: the count of lines containing "root." In the verification environment it was 272. This pattern of counting "how many places is it in?" is the standard technique for tallying event occurrences in logs. Check it yourself — your environment’s number will differ.)

3-6. Line Numbers for grep Too — The -n Option

When search results are long, "which line number" matters:

grep -n "root" /etc/passwd
1:root:x:0:0:root:/root:/bin/bash

(Verified 2026-09-09.)

How to read it: the number at the front of the line is the line number. A coordinate is attached: "found on line 1." Later, when you’re told "fix line 25 of this file" or when pinpointing an event’s location in a log, this number becomes your coordinate. It’s an option that costs nothing to add out of habit.

3-7. The Two Tools Cooperate — find, Then grep

Let’s experience one field pattern: "among files changed in the last day, those with log in the name":

find ~ -mtime -1 2>/dev/null | grep log
/root/stream-lab/live.log
/root/test-note.log

(Verified 2026-09-09 — in the verification environment, Step 19’s live.log and an experimental test-note.log were caught. In your environment, you’ll see the live.log you made in Step 19.)

Reading the structure: find conducts the first-pass investigation by time → grep conducts the second-pass investigation by name. Two tools chained by a pipe continue the investigation. This "narrow down, then narrow again" is the basic tactic of searching.


4. Missions & Exercises

Mission — The Trace-Finding Game

First, create the materials:

mkdir -p ~/search-game/deep/nested
echo "this file contains the secret token hunter2" > ~/search-game/deep/nested/clue.txt
echo "a file with nothing in it" > ~/search-game/normal.txt

Now become the investigator:

  1. Task 1: find clue.txt by name alone (use find)
  2. Task 2: find the file containing the string "hunter2" by content (use grep -r)
  3. Task 3: list every file changed today (in the last day) in your home
  4. Task 4: with history | grep grep, count how many times you used grep today (hint: append | wc -l)

How to verify yourself: if Tasks 1 and 2 point to the same file, you’re correct. Two tools finding the same needle via different paths — that contrast is the summary of today’s chapter.

Exercises

Question 1. For each situation, should you use grep or find? ① finding a file with config in its name ② finding lines containing the text "ERROR" ③ finding files changed within the last day

Question 2. Split 2>/dev/null into its three parts — 2, >, /dev/null — and explain each one’s meaning.

Question 3. Why does a problem occur if you drop the quotes around the pattern, as in find ~ -name *.txt? Who interprets the * first?

Question 4. You searched a log for "error" and got 0 results even though the word is definitely there. What should you suspect first, and what option solves it?


5. Model Answers & Completion Criteria

Mission Model Answer

# Task 1 — by name
find ~ -name "clue.txt" 2>/dev/null
/root/search-game/deep/nested/clue.txt
# Task 2 — by content
grep -r "hunter2" ~/search-game 2>/dev/null
/root/search-game/deep/nested/clue.txt:this file contains the secret token hunter2

(Verified 2026-09-09 — in your environment, /home/username appears where /root is.)

# Task 3 — last day
find ~ -mtime -1 2>/dev/null

# Task 4 — number of grep uses
history | grep grep | wc -l

How to verify: ① Do Tasks 1 and 2 point to the same path (.../deep/nested/clue.txt)? If the two tools found the same needle via different paths, you’re done. ② Does Task 3’s list include the search-game files you just made? ③ Is Task 4’s number roughly the number of greps you actually typed (history also includes the search command you just ran)?

Something deeper to think about: the command an attacker uses after breaking in to find files containing the word "password" is exactly today’s grep -r. And the defender’s detection clues live in Step 18’s .bash_history and Step 12’s logs — offense and defense meet on top of the same commands.

Exercise Answers

Answer 1. ① find (name condition) ② grep (content) ③ find (time attribute). "Name, size, or time → find; content → grep" is the entire distinction.

Answer 2. 2 is the number of the standard error (stderr) pipe, > is the redirection that changes output direction, and /dev/null is the trash-can file where everything that goes in disappears. Together: "throw away the errors and show me only the normal results."

Answer 3. The shell (bash) interprets the * before find ever sees it — it expands it into the filenames of the current directory, so find receives something other than what you intended. Wrapping it in quotes like "*.txt" delivers the pattern to find intact. "Deliver the pattern to find directly" — the quotes are that courier.

Answer 4. Suspect a case mismatch first — Linux treats Error and error differently. Use grep -i to ignore case. Log text is wildly inconsistent about case, so -i is practically a default option in log searches.

Completion Checklist

  • [ ] I can explain the difference between grep and find (content vs. name/conditions)
  • [ ] I can search the contents of whole folders with grep -r
  • [ ] I can use the -i (ignore case) and -n (line numbers) options
  • [ ] I can explain each part of 2>/dev/null (2, >, /dev/null)
  • [ ] I can search by name, size, and time conditions with find
  • [ ] I can find past commands with history | grep
  • [ ] I have connected find and grep with a pipe
  • [ ] Mission: I completed all 4 tasks of the trace-finding game

6. Common Pitfalls & Fixes

Wall 1. I ran grep and errors carpeted the screen

Symptom: dozens of lines like grep: /etc/shadow: Permission denied.
Cause: you’re searching folders you lack permission for — it’s normal, which is why a stock phrase exists (see the Section 3-2 verification).
Fix: append 2>/dev/null to the end of the command. And reread Section 2-3 on why it works — a tool you understand is never forgotten.

Wall 2. The pattern after find’s -name doesn’t work

Symptom: find ~ -name *.txt gives strange results or errors.
Cause: * must be wrapped in quotes. Unwrapped, the shell interprets it first and find receives a different meaning.
Fix: always wrap it in quotes, like "*.txt".

Wall 3. grep results just say "binary file matches"

Symptom: instead of content, a "binary file matches"-type message.
Cause: your search targets include program files (binary files) rather than documents, and the text happened to match inside one.
Fix: at this stage, you can ignore it. Just know that "fragments of text can match even in non-text files." Binary file analysis is a much later topic (Level 3).

Wall 4. find takes forever

Symptom: you ran find / and it won’t finish for ages.
Cause: it’s searching the entire system (hundreds of thousands of files) — normal.
Fix: stop it with Ctrl + C and narrow the search scope. Looking first in "places where it’s likely to be," like /etc or ~, is the correct order of investigation. Narrowing the scope is investigative skill.

Wall 5. The search works but case kept it from finding anything

Symptom: the word is definitely there but 0 results.
Cause: case mismatch. Linux treats Error and error differently.
Fix: make grep -i a habit. Especially in log searches, -i is practically a default option.


7. Summary

Today’s Concepts

Concept One-line description
grep A magnifying glass that finds lines by content
find An investigator that finds files by name, size, and time conditions
Wildcard (*) "Any characters" — deliver it to find wrapped in quotes
/dev/null Linux’s trash-can file — where errors are discarded
Narrowing tactic find first, grep second — investigation is a chain

Today’s Commands

Command What it does
grep -rin "word" folder Content search: whole folder, ignore case, with line numbers
find folder -name "pattern" Find by name
find folder -size +10M / -mtime -1 Find by size / recent modification time
command 2>/dev/null Send errors to the trash
grep ... | wc -l Count how many matches
find ... | grep ... Second-pass investigation after the first
history | grep word What was that command again?

More Important Than Commands: The Instinct

Most of breach investigation ultimately comes down to "searching" — finding suspicious strings, finding recently changed files, finding records from a specific time. A real day at an analysis site is a chain like "grep the suspicious IP → grep what that IP did → grep other records from that time window," where each search’s result becomes the next search’s clue. What you learned today is the first link of that chain.

Remember two more things. First, there are dedicated commands for asking "where is an installed program," like which python3 — a shortcut faster than find. Second, practitioners collect their well-crafted search commands in personal notes. Search skill is ultimately "the ability to narrow a question," and for that reasoning to be accurate, you must know the system’s structure — search skill is a measure of system understanding.


Once every box is checked, Step 20 is complete.