text
string
linux

Find all files containing a specific text (string) on Linux?

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Introduction

To find all files containing a specific text string on Linux, use grep -Rl "search_string" . for a recursive search that prints matching file names. For faster results on source code trees, use rg -l "search_string" (ripgrep). Both commands search recursively from the current directory and handle most day-to-day scenarios.

bash
1# List files containing "TODO" in the current directory tree
2grep -Rl "TODO" .
3
4# Same thing with ripgrep (faster, respects .gitignore)
5rg -l "TODO"

grep: The Standard Tool

grep is installed on virtually every Linux system. The recursive flags and output options cover the majority of file search tasks.

bash
grep -Rl "database_url" /etc/

The -R flag searches recursively through all subdirectories. The -l flag tells grep to print only the file names that contain at least one match, not the matching lines themselves.

bash
grep -Rn "database_url" /etc/

The -n flag adds line numbers to each match, which helps you jump directly to the relevant location in the file.

bash
grep -Rli "error" /var/log/

The -i flag makes the search case-insensitive, so it matches Error, ERROR, error, and any other case variant.

Filter by File Extension

bash
1# Search only Python files
2grep -Rn --include='*.py' "import requests" .
3
4# Search only configuration files
5grep -Rn --include='*.conf' --include='*.cfg' "max_connections" /etc/
6
7# Exclude test files
8grep -Rn --exclude='*_test.go' "func main" .

Exclude Directories

bash
grep -Rn --exclude-dir=node_modules --exclude-dir=.git --exclude-dir=vendor "API_KEY" .

Excluding generated and dependency directories prevents noise and speeds up the search dramatically.

Useful grep Flag Combinations

FlagsPurposeExample
-RlRecursive, file names onlygrep -Rl "TODO" .
-RnRecursive, with line numbersgrep -Rn "TODO" .
-RniRecursive, line numbers, case-insensitivegrep -Rni "error" /var/log/
-RnlRecursive, file names only, case-insensitiveNot valid (use -Rli)
-RnIRecursive, line numbers, skip binary filesgrep -RnI "config" .
-RcRecursive, count matches per filegrep -Rc "TODO" .
-RwRecursive, whole word matchgrep -Rw "port" .

ripgrep (rg): The Faster Alternative

ripgrep is significantly faster than grep on large codebases because it uses parallelism, respects .gitignore rules by default, and skips binary files automatically.

bash
1# Search recursively from the current directory (default behavior)
2rg "search_string"
3
4# File names only
5rg -l "search_string"
6
7# Case-insensitive
8rg -li "search_string"

Filter by File Type

ripgrep has built-in file type awareness:

bash
1# Search only Python files
2rg -t py "import requests"
3
4# Search only JavaScript and TypeScript files
5rg -t js -t ts "addEventListener"
6
7# List available file types
8rg --type-list

Filter by Glob Pattern

bash
1# Search only files matching a glob
2rg -g '*.yml' "version:" .
3
4# Exclude a pattern
5rg -g '!*.min.js' "function" .

Show Context Around Matches

bash
1# 3 lines before and after each match
2rg -C 3 "panic" .
3
4# 5 lines after each match
5rg -A 5 "ERROR" /var/log/app.log

Combining find and grep

When the file selection criteria go beyond name patterns, find gives you more control:

bash
1# Search files modified in the last 7 days
2find /var/log -type f -mtime -7 -exec grep -l "timeout" {} +
3
4# Search files larger than 1MB
5find . -type f -size +1M -name '*.log' -exec grep -l "OutOfMemory" {} +
6
7# Search files owned by a specific user
8find /home -type f -user deploy -exec grep -l "config" {} +

The {} + syntax passes multiple file names to grep in batches, which is faster than {} \; (which spawns a new grep process per file).

The xargs Alternative

bash
find . -name '*.java' -print0 | xargs -0 grep -l "deprecated"

The -print0 and -0 flags use null bytes as delimiters, which handles file names containing spaces or special characters correctly.

Fixed Strings vs. Regular Expressions

By default, both grep and rg interpret the search pattern as a regular expression. Characters like ., *, [, (, and ? have special meaning:

bash
1# This searches for the regex pattern "error[42]", matching "error4" or "error2"
2grep -Rn "error[42]" .
3
4# To search for the literal string "error[42]", use fixed-string mode
5grep -RFn "error[42]" .
6rg -F "error[42]"

Use fixed-string mode (-F) whenever you are searching for literal text that contains regex metacharacters.

Performance Comparison

Tool100K files (warm cache).gitignore awareBinary skipParallel
grep -RSlow (single-threaded)NoManual (-I flag)No
grep -R with excludesModerateNoManualNo
rgFastYes (default)Yes (default)Yes
find + grepModerateNoManualNo
ag (The Silver Searcher)FastYesYesYes

For large repositories, rg is typically 2-10x faster than grep -R due to parallelism and automatic exclusion of irrelevant files.

Searching Compressed Files

Log files are often compressed with gzip. Use zgrep to search without decompressing first:

bash
1zgrep "error" /var/log/syslog.*.gz
2
3# Recursive with zgrep is not supported, but you can combine with find
4find /var/log -name '*.gz' -exec zgrep -l "error" {} +

Practical Recipes

bash
1# Find all files containing a hardcoded IP address
2grep -Rn '[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}' .
3
4# Find TODO comments across a project
5rg -n "TODO|FIXME|HACK" --type-add 'src:*.{py,js,ts,java,go}' -t src .
6
7# Find files containing a string but NOT another string
8grep -Rl "import flask" . | xargs grep -L "from flask import"
9
10# Count occurrences across all files
11rg -c "console.log" --type js | sort -t: -k2 -rn | head -20

Common Pitfalls

Forgetting -l when you only need file names produces a wall of matching lines that is hard to parse. Use -l for file lists and -n for line-level detail.

Treating the search pattern as a literal string when the tool interprets it as a regex causes unexpected matches. A search for user.name also matches username because . means "any character" in regex. Use -F for literal searches.

Searching large trees without excluding directories like node_modules, .git, vendor, or build wastes time and produces irrelevant results. Always add --exclude-dir flags (for grep) or rely on .gitignore (for rg).

Using find -exec grep {} \; instead of find -exec grep {} + spawns a separate grep process for every file, which is significantly slower on large file sets.

Searching binary files without the -I flag (grep) produces unreadable output and slows the search. ripgrep skips binary files by default, but grep does not.

Summary

  • Use grep -Rl "text" . to list files containing a string recursively.
  • Use grep -Rn when you need line numbers and matching lines.
  • Use rg (ripgrep) for faster searches that automatically respect .gitignore and skip binary files.
  • Combine find and grep when you need to filter files by attributes like modification time, size, or ownership.
  • Use fixed-string mode (-F) when the search text contains regex special characters.
  • Exclude dependency and generated directories to keep searches fast and relevant.

Free course
Beginner
7 lessons
2 hours
Tackling System Design Interview Problems

A short course that equips you with the skills to approach system design interviews methodically.

Start the free course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

All Rights Reserved.