Skip to content

05 - Searching

What this session is

About 30 minutes. You'll learn grep (search inside files), find (search the filesystem), locate (fast filename search), and a couple of modern alternatives.

grep: search inside files

grep "pattern" file.txt           # lines containing "pattern"
grep "error" /var/log/syslog      # lines containing "error" in a log file
grep -i "error" file.txt          # case-insensitive
grep -n "error" file.txt          # show line numbers
grep -r "pattern" /etc            # recursive (search all files in /etc)
grep -v "pattern" file.txt        # inverse - lines NOT containing
grep -c "pattern" file.txt        # count of matching lines

grep is the most-used search tool in Linux. Memorize it.

You can pass multiple files:

grep "TODO" *.md                  # search all .md files in current directory

Patterns are regular expressions ("regex"). Simple cases (literal text) just work. For real regex (., *, [], ^, $), look it up when you need it.

Useful flag combo: -rni = recursive, line numbers, case-insensitive. Probably what you want when looking for something in a codebase.

Modern alternative: ripgrep (rg)

ripgrep is grep rewritten in Rust - much faster, smarter defaults (ignores hidden + gitignored files), more readable output. Install:

  • macOS: brew install ripgrep
  • Linux: sudo apt install ripgrep or sudo dnf install ripgrep
rg "pattern"            # search recursively from current directory
rg "pattern" path/      # search in a specific directory
rg -i "pattern"         # case-insensitive
rg -t py "TODO"         # search only Python files

Use rg over grep in interactive use; learn grep because it's universally available.

find: search the filesystem

find /path -name "pattern"            # files matching name
find . -name "*.txt"                  # all .txt files under current dir
find ~ -type d -name "Documents"      # directories named Documents in your home
find /var/log -type f -mtime -1       # files modified in the last 1 day
find . -size +10M                     # files larger than 10MB
find . -empty                         # empty files or directories

find is powerful and verbose. The basic shape: find <where> <criteria> [<action>].

Common criteria: - -name "pattern" - filename matches. - -type f / -type d - files / directories only. - -size +N / -size -N - bigger / smaller than N (with k/M/G suffixes). - -mtime -N / -mtime +N - modified less than / more than N days ago.

You can combine:

find ~/Documents -type f -name "*.pdf" -size +1M

That finds PDFs larger than 1MB in ~/Documents.

Common action: -delete (be careful) or -exec command {} \;:

find /tmp -type f -name "*.log" -mtime +7 -delete       # delete old log files
find . -name "*.bak" -exec rm {} \;                     # same idea, more flexible

The {} is replaced with each matching file. The \; ends the -exec command.

find searches in real time. locate searches an indexed database (much faster but might be stale).

locate filename.txt
locate -i Filename                 # case-insensitive

Install if not present: sudo apt install plocate (or mlocate). Run sudo updatedb to refresh the index.

Use locate for quick "where is that file again?"; use find for criteria-based searches or anything in directories you've just modified.

Modern alternative: fd

fd is to find what rg is to grep - Rust rewrite, faster, friendlier defaults.

fd pattern                # find files matching pattern (basename)
fd -e txt                 # find .txt files
fd -t d Documents         # find directories

Install: brew install fd / sudo apt install fd-find (called fdfind on Debian/Ubuntu).

Putting it together

A real session: find every file mentioning "TODO" in your code project's Python files:

cd ~/projects/myapp
grep -rn "TODO" --include="*.py"
# or with rg:
rg -t py "TODO"

Find log files older than a week:

find /var/log -type f -mtime +7

Find where the python3 binary lives:

which python3
# or
locate python3 | head

Exercise

  1. In ~/practice (from page 03 - recreate if needed), create some files with content:

    echo "this has TODO inside" > a.txt
    echo "no special marker here" > b.txt
    echo "another TODO here" > c.txt
    mkdir nested
    echo "TODO in nested" > nested/d.txt
    

  2. Find all files containing "TODO":

    grep -rn "TODO" .
    
    You should see 3 results across 3 files.

  3. Find all .txt files in your home directory:

    find ~ -type f -name "*.txt"
    

  4. Find empty directories:

    find ~ -type d -empty
    

  5. Search a system file: find every line in /etc/services mentioning port 22:

    grep "22/" /etc/services
    

  6. Bonus: if you have ripgrep installed, run rg "TODO" from your ~/practice. Compare speed and output to grep.

What you might wonder

"When should I use grep -r vs find + grep?" - grep -r works for simple "find pattern in any file under here." - find + grep for "files matching criteria AND content matching pattern": find . -name "*.py" -mtime -7 -exec grep -l "TODO" {} +.

"What's which?" which command shows the path to the executable that would run when you type command. which python3/usr/bin/python3 typically.

"Are regex patterns the same in grep as in Python?" Mostly. Basic regex is universal. Some advanced features differ; grep -E uses extended regex (closer to Perl/Python). When in doubt, test.

Done

  • Search inside files with grep (-r, -n, -i, -v).
  • Search the filesystem with find (by name, type, size, mtime).
  • Quick name lookups with locate.
  • Recognize modern alternatives rg and fd.

Next: Permissions and users →

Comments