Bash Search Text (grep)
Search for patterns in files and text
🔍 What is grep?
grep searches for text patterns in files or input. It's one of the most powerful tools for finding specific content, filtering output, and analyzing text data quickly and efficiently.
# Search for "error" in a file
grep "error" logfile.txt
# Search in multiple files
grep "TODO" *.js
grep Basics
Basic Search
Find text in files
grep "pattern" file.txt
Case Insensitive
Ignore case when searching
grep -i "pattern" file.txt
Line Numbers
Show matching line numbers
grep -n "pattern" file.txt
Recursive Search
Search in all subdirectories
grep -r "pattern" /path
🔹 Basic grep Usage
The grep command is the primary tool for searching plain-text data sets for lines matching a regular expression or fixed string. Its basic form, grep "search_term" filename, scans the file and outputs every line containing the term. This simple functionality is the bedrock of countless operations: sifting through multi-gigabyte log files for errors, searching source code for function definitions, or filtering command output. Its efficiency and ubiquity make it one of the most frequently used commands in Unix-like operating systems.
# Search for "error" in a log file
grep "error" app.log
# Search for "function" in a JavaScript file
grep "function" script.js
# Search for multiple patterns using pipe
grep "error" app.log | grep "database"
Output:
Error: Connection timeout Error: Database not found Fatal error: Out of memory
🔹 Case-Insensitive Search
The -i flag makes grep ignore case distinctions, broadening search results to include all capitalization variants. This is essential when the text's case is unpredictable, such as in user-generated content, mixed-case log messages (e.g., "Error", "ERROR", "error"), or programming languages with case-insensitive identifiers. Using -i ensures comprehensive searches without needing to construct complex regular expressions with character classes for every possible case combination, streamlining the search process significantly.
# Find "error" in any case (error, Error, ERROR)
grep -i "error" app.log
# Find "warning" regardless of case
grep -i "warning" system.log
# Combine with other options
grep -in "todo" *.js
Output:
Error: Connection failed error: Invalid input ERROR: System crash Fatal error occurred
🔹 Showing Line Numbers
Adding -n to a grep command prefixes each matching line with its corresponding line number within the file. This context is invaluable for developers needing to jump to a specific line in an editor, for system administrators referencing line numbers in trouble tickets, or for scripts that need to record the location of patterns for later processing. It transforms grep from a mere filter into a location-finding tool, bridging the gap between searching and acting on the results.
# Show line numbers with matches
grep -n "function" script.js
# Combine with case-insensitive search
grep -in "error" app.log
# Show line numbers for multiple files
grep -n "import" *.py
Output:
15:function calculateTotal() {
28:function validateInput(data) {
42:function processRequest() {
🔹 Recursive Search
The -r (or -R) option enables grep to descend recursively through directory trees, searching all files. Combined with -l (list files), it can quickly identify which files in a project contain a specific keyword, license header, or TODO comment. This recursive capability is fundamental for codebase exploration, log directory analysis, and configuration management, allowing you to perform wide-ranging searches without manually specifying hundreds of individual file paths.
# Search recursively in current directory
grep -r "TODO" .
# Search recursively with line numbers
grep -rn "import React" src/
# Show only filenames containing pattern
grep -rl "database" /var/www/
# Exclude certain directories
grep -r --exclude-dir=node_modules "error" .
Output:
./src/app.js:// TODO: Add error handling ./src/utils.js:// TODO: Optimize this function ./components/Header.js:// TODO: Add responsive design
🔹 Counting Matches
The -c option suppresses line output and instead prints a count of matching lines for each input file. This is perfect for generating high-level summaries: counting how many times an API endpoint was called in a log, how many users are listed in a database dump, or how many compilation errors occurred. It provides a quantitative measure at a glance, often used in the first stage of log analysis to gauge the severity or frequency of an issue before diving into the detailed content.
# Count matching lines
grep -c "error" app.log
# Count case-insensitive matches
grep -ic "warning" system.log
# Count in multiple files
grep -c "function" *.js
Output:
app.log:47 system.log:12 script.js:8 utils.js:15
🔹 Inverting Matches
Using -v inverts the match logic, causing grep to output lines that do not contain the given pattern. This is a powerful filtering technique. Common uses include removing comments (lines starting with # or //) from configuration or code files, excluding healthy "OK" status messages from monitoring output to see only warnings and errors, or filtering out known-bad IP addresses from a list. It effectively lets you define what to exclude, cleaning up data by subtraction.
# Show lines that don't contain "error"
grep -v "error" app.log
# Exclude comment lines
grep -v "^#" config.txt
# Exclude blank lines
grep -v "^$" file.txt
# Chain multiple exclusions
grep -v "debug" app.log | grep -v "info"
Output (excluding "error"):
Info: Application started Warning: Low memory Info: Request processed successfully
🔹 Using Regular Expressions
sed integrates regular expressions deeply, using them not just in the s command but also for selecting lines to process. Anchors (^ for line start, $ for line end), character classes, and quantifiers allow for precise pattern specification. This enables sophisticated tasks like normalizing whitespace, validating input formats, or extracting substrings. Mastery of regex in sed unlocks its full potential, transforming it from a simple line editor into a powerful text processing engine.
# Match lines starting with "Error"
grep "^Error" app.log
# Match lines ending with semicolon
grep ";$" script.js
# Match email addresses
grep -E "[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}" contacts.txt
# Match phone numbers
grep -E "[0-9]{3}-[0-9]{3}-[0-9]{4}" data.txt
# Match either "error" or "warning"
grep -E "error|warning" app.log
Output:
Error: Connection failed Error: Invalid credentials warning: Deprecated function used
🔹 Context Lines
The context options -A (after), -B (before), and -C (context) display surrounding lines for each match. When debugging, seeing the lines before an error often reveals its cause, and seeing lines after shows its impact. For example, grep -B2 -A2 "segmentation fault" crash.log provides a mini-backtrace. This feature adds crucial situational awareness to search results, preventing the "line in a vacuum" problem and making grep much more informative for diagnostic work.
# Show 2 lines after each match
grep -A 2 "error" app.log
# Show 3 lines before each match
grep -B 3 "exception" app.log
# Show 2 lines before and after
grep -C 2 "warning" system.log
Output (grep -A 2):
Error: Connection timeout at Database.connect() at line 45 in db.js
🔹 Useful grep Options
Beyond basics, options like --color for highlighting, -w for whole-word matches, and -o for printing only the matched text refine searches. --color=auto makes matches visually pop in the terminal. -w ensures you match "word" but not "password". -o is excellent for extracting specific substrings, like pulling all email addresses from a document. Combining these options allows you to craft precise, targeted search commands for highly specific text-processing scenarios.
Common Options:
- -i: Case-insensitive search
- -n: Show line numbers
- -r: Recursive search
- -v: Invert match (exclude pattern)
- -c: Count matching lines
- -l: Show only filenames
- -w: Match whole words only
- -o: Show only matched text
- --color: Highlight matches
# Match whole word only
grep -w "test" file.txt
# Show only the matched text
grep -o "error" app.log
# Highlight matches in color
grep --color "warning" system.log
# Multiple options combined
grep -rni "TODO" src/