DaleSchool

Search and Filter

Beginner25min

Learning Objectives

  • Search for text in files using grep
  • Chain commands with pipes (|) to handle complex tasks
  • Search the file system for files matching specific criteria with find

Working Code

Example 1: Searching text with grep

Start with a file to search:

cat Documents/notes.md

Output:

# Notes
- item 1
- item 2

Find lines containing a specific word:

grep "item" Documents/notes.md

Output:

- item 1
- item 2

Show line numbers too:

grep -n "item" Documents/notes.md

Output:

2:- item 1
3:- item 2

Example 2: Case-insensitive search

grep -i "hello" Documents/hello.txt

Output:

Hello, World!

The -i option ignores case. It matches Hello, hello, and HELLO alike.

Example 3: Chaining commands with pipes

# Filter ls output for a specific pattern
ls | grep ".md"

Output:

notes.md
# Count items in a file listing
ls | wc -l

Output:

       4
# 3-stage pipe: ls -> grep -> wc
ls | grep ".txt" | wc -l

Output:

       1

Try It Yourself

grep with Various Options

# Search across multiple files
grep "Hello" Documents/hello.txt Documents/notes.md

# Recursive search through subdirectories
grep -r "item" Documents/

# Show only filenames (not content)
grep -rl "Hello" .

# Show match count only
grep -c "item" Documents/notes.md

Output:

2
# Show non-matching lines (inverse search)
grep -v "item" Documents/notes.md

Output:

# Notes

Finding Files with find

# Find files by name
find . -name "*.txt"

Example output:

./Documents/hello.txt
./Downloads/readme.txt
# Filter by type (f=file, d=directory)
find . -type f -name "*.md"

# Files modified within the last day
find . -mtime -1

# Files larger than a specific size
find . -size +1k
# Run a command on each found file (-exec)
find . -name "*.txt" -exec cat {} \;

"Why?" — Why Pipes Are Powerful

The pipe (|) connects one command's stdout to the next command's stdin.

ls -la | grep ".txt" | wc -l
   |          |           |
file list  .txt filter  count lines

Step by step:

  1. ls -la — list files
  2. grep ".txt" — keep only lines containing .txt
  3. wc -l — count remaining lines

Result: the number of .txt files in the current directory.

The core principle of pipes: combine simple tools to tackle complex tasks. Each command does one thing well, and pipes connect them to solve bigger problems.

grep Options Summary

| Option | Description | Example | | ------ | ---------------------- | ----------------- | | -i | Ignore case | grep -i "hello" | | -n | Show line numbers | grep -n "error" | | -r | Include subdirectories | grep -r "bug" . | | -l | Show filenames only | grep -rl "todo" | | -v | Exclude matches | grep -v "#" | | -c | Count matching lines | grep -c "error" |

grep and Pipes in Practice

# Find errors in a log
cat app.log | grep "ERROR"

# Count error lines
cat app.log | grep "ERROR" | wc -l

# View everything except debug lines
cat app.log | grep -v "DEBUG"

# Find a function in source code
grep -rn "getUserById" src/

Common Mistakes

Mistake 1: Special characters in grep patterns

# . means "any character" in regex
grep "file.txt" .    # matches file.txt AND file_txt

# To search literally, escape it
grep "file\.txt" .
# Or use -F (fixed string)
grep -F "file.txt" .

Mistake 2: Searching a directory without -r

grep "text" Documents/   # error
# grep: Documents/: Is a directory

grep -r "text" Documents/  # correct

Mistake 3: Piping find results to grep incorrectly

# Wrong: this searches filenames, not file contents
find . -name "*.txt" | grep "hello"   # finds files with "hello" in the name

# Correct: search file contents
grep -r "hello" --include="*.txt" .

Deep Dive

Pattern searching with regex

grep supports regular expressions:

# ^ : start of line
grep "^-" Documents/notes.md

# $ : end of line
grep "2$" Documents/notes.md

# . : any single character
grep "ite.1" Documents/notes.md

# []: one character from a set
grep "[12]" Documents/notes.md

# Extended regex (-E)
grep -E "item [12]" Documents/notes.md

Regex is powerful but can be tricky at first. Basic grep options handle most searches, so learn regex as needed.

The powerful -exec option in find

Run a command on each found file:

# Delete all .log files
find . -name "*.log" -exec rm {} \;

# Print contents of all .txt files
find . -name "*.txt" -exec cat {} \;

# Save found file list to a file (using redirection)
find . -name "*.md" > md-files.txt

{} is replaced with the found file path, and \; marks the end of the command.

Why developers use ripgrep (rg) instead of grep

Many developers prefer rg (ripgrep):

brew install ripgrep

# Basic usage (similar to grep -r)
rg "functionName" src/

# Automatically respects .gitignore
# Color output by default
# Tens of times faster than grep

Especially effective on large codebases with tens of thousands of files. VS Code's search feature uses ripgrep internally.

  1. Search for text with grep "Hello" Documents/hello.txt.
  2. Search with line numbers using grep -n "item" Documents/notes.md.
  3. Count matching lines with grep -c "item" Documents/notes.md.
  4. List only .txt files with ls | grep ".txt".
  5. Search the entire current directory with grep -r "Hello" ..

Q1. What does ls | grep ".txt" | wc -l output?

  • A) The contents of .txt files
  • B) The number of items containing ".txt" in their name in the current directory
  • C) The total size of .txt files
  • D) A list of .txt files