PQ
PQ.Hosting

Currency

Searching Files by Content in Linux: grep and Beyond

Author
PQ
February 25, 2026
5 min read
20 views

"Find the file where this string is mentioned" — the task comes up constantly. Where did traffic go, where is the old domain configured, which config file has a stale database password — content search answers all of it. There are several tools available, each with its own strengths.

grep — The Main Tool

grep stands for global regular expression print. It reads files and prints lines that match a pattern.

Basic syntax:

grep [options] "pattern" file_or_path

The most common server use case — recursive search through a directory:

grep -r "search_string" /path/to/directory

The -r flag makes grep traverse all subdirectories. Without it, grep only looks at the specified file or list of files.

Flags That Get Used in Practice

-i — case doesn't matter

grep -ri "error" /var/log/nginx/

With this flag, Error, ERROR and error are treated as identical. In practice, essential when searching logs where severity levels may be formatted differently.

-n — line numbers in output

grep -n "listen 80" /etc/nginx/nginx.conf

Shows exactly which line a match was found on. Useful when you need to open the file in an editor and jump directly to the right spot.

-l — filenames only

grep -rl "database_name" /etc/

Instead of printing matching lines — just a list of files where the pattern appeared. When there are many results and you need to understand the scope first.

-c — match count

grep -c "POST" /var/log/nginx/access.log

Outputs the number of matching lines rather than the lines themselves. A quick way to see how many POST requests are in the log without scrolling through it.

-v — inverted search

grep -v "127.0.0.1" /var/log/nginx/access.log

Shows lines where the pattern does not appear. Useful for filtering out local requests from a log to see only external traffic.

-A, -B, -C — context around a match

grep -A 3 "fatal error" /var/log/php/error.log

-A 3 prints 3 lines after each match. -B 3 — 3 lines before. -C 3 — 3 lines on both sides. Indispensable when reading stack traces in logs.

Flag Combinations for Real Tasks

Find all configs mentioning a specific IP

grep -rn "192.168.1.100" /etc/ --include="*.conf"

--include restricts the search to files with a specific extension. Without it, grep digs into binaries and everything irrelevant.

Search for multiple patterns at once

grep -E "error|warning|critical" /var/log/syslog

The -E flag enables extended regular expressions. The pipe character acts as logical OR — finds lines containing any of the three words.

Exclude certain files from search

grep -r "old_domain.com" /var/www/ --exclude="*.log" --exclude-dir=".git"

--exclude and --exclude-dir remove unwanted paths — logs, cache, git repositories.

Count unique IPs from an access log

grep -oE "\b([0-9]{1,3}\.){3}[0-9]{1,3}\b" /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -20

-o prints only the matched portion of each line, not the full line. Combined with sort and uniq, this produces a top-20 IP list ranked by request count.

Searching Compressed Logs: zgrep

Logs on servers are often rotated and compressed into .gz archives. Regular grep cannot read them — that is what zgrep is for:

zgrep "error" /var/log/nginx/error.log.2.gz

Works identically to grep but reads gzip archives directly. Same syntax, same flags.

To search across all rotated logs at once:

zgrep -h "critical" /var/log/nginx/error.log*.gz

-h suppresses filenames from the output — useful when only the line content matters.

ripgrep — A Faster Alternative

rg (ripgrep) is a modern replacement for grep, written in Rust. On large codebases and directories it runs significantly faster through parallel file traversal.

Installation:

apt install ripgrep

Basic usage follows the same syntax:

rg "string" /path

Key differences from grep:

  • automatically ignores .git, node_modules, and anything in .gitignore
  • recursive mode is on by default
  • colored output with match highlighting out of the box
  • supports compressed file search with the -z flag
rg -z "error" /var/log/

For a one-off check the difference is negligible. On a project with thousands of files — substantial.

find + grep: When File Attribute Filtering Is Needed

Sometimes the search should be limited to files modified in the last 24 hours, or only to files under a certain size. Here grep needs help from find:

find /var/www -name "*.php" -mtime -1 | xargs grep -l "eval("

Finds .php files modified in the past day and checks each one for eval( — a classic indicator of injected malicious code.

find /etc -type f -size -10k | xargs grep -rn "password"

Searches for the word password only in files smaller than 10 kilobytes — cuts out large binaries and media files.

xargs passes find results as input to grep. Without it the command would be considerably more complex.

Quick Reference

Task Command
Recursive search through a directory grep -r "string" /path/
Case-insensitive search grep -ri "string" /path/
Show line numbers grep -n "string" file
Filenames with matches only grep -rl "string" /path/
Inverted search grep -v "string" file
Context around matches grep -C 3 "string" file
Only .conf files grep -r "string" /path/ --include="*.conf"
Search compressed logs zgrep "string" file.gz
Multiple patterns grep -E "a|b|c" file
Via find with filtering find /path -name "*.php" | xargs grep "string"

Summary

For most tasks grep -rn with the right flag covers everything. Compressed logs — zgrep. A large project with thousands of files — worth installing ripgrep. Search with date or size filtering — find piped into xargs grep.

All of this works on any Linux server without additional configuration. If a server is still needed — the PQ.Hosting catalog has options across a wide range of locations and configurations.

Share this article