Two commands handle most of the searching you’ll ever do on a Linux server:
find
locates files,
grep
searches inside them. Between the two, you can track down just about anything.
These aren’t obscure tools. They’re the kind of commands you’ll run multiple times a day once you’re comfortable with them. Need to find every
.log
file modified in the last 24 hours?
find
. Need to figure out which config file contains a specific database hostname?
grep
. Need to do both at once? Pipe them together.
This guide covers both commands in depth, from basic usage through advanced patterns, plus a few alternative tools worth knowing about.
Finding files with find#
The
find
command walks a directory tree and returns files that match your criteria. Unlike
ls
, which only shows the current directory,
find
goes as deep as you want, checking every subdirectory along the way.
Basic file search
The simplest use: find a file by name.
find /var/www -name "wp-config.php"
This searches
/var/www
and everything below it for a file named
wp-config.php
. The path at the beginning tells
find
where to start. Use
.
for the current directory,
/
for the entire filesystem, or any specific path.
Wildcard patterns
When you don’t know the exact filename, wildcards help. The asterisk matches any sequence of characters:
find /var/log -name "*.log"
This returns every file ending in
.log
under
/var/log
. Wrap the pattern in quotes so the shell doesn’t expand the wildcard before
find
gets to it. This is a common gotcha; without quotes, the shell tries to match
*.log
against files in the current directory instead of passing the pattern to
find
.
You can also match partial names:
find . -name "backup*"
This catches
backup.sql
,
backup-2026-02-15.tar.gz
,
backup_notes.txt
, and anything else starting with “backup.”
Filtering by type
By default,
find
returns both files and directories. Narrow it down with
-type
:
# Only regular files
find /etc -type f -name "*.conf"
# Only directories
find /home -type d -name "public_html"
# Only symbolic links
find /usr/local -type l
Filtering by modification time
This is where
find
becomes genuinely useful for server administration. When something breaks at 3 AM and you need to figure out what changed, modification time filters are the answer.
# Files modified in the last 24 hours
find /etc -type f -mtime -1
# Files modified more than 30 days ago
find /var/log -type f -mtime +30
# Files modified in the last 2 hours (use -mmin for minutes)
find /var/www -type f -mmin -120
The number after
-mtime
is in days. A minus sign means “less than,” a plus sign means “more than,” and no sign means “exactly.” The
-mmin
variant works the same way but counts minutes instead of days.
Filtering by size
Track down files eating your disk space:
# Files larger than 100MB
find / -type f -size +100M
# Files larger than 1GB
find / -type f -size +1G
# Files smaller than 1KB (possibly empty or stub files)
find /var/www -type f -size -1k
Filtering by owner
Useful when cleaning up after a user or tracking down permission issues:
# Files owned by a specific user
find /home -type f -user john
# Files owned by a specific group
find /var/www -type f -group www-data
Combining criteria
find
lets you chain multiple conditions. By default, all conditions must be true (AND logic):
# PHP files modified in the last 3 days, larger than 10KB
find /var/www -type f -name "*.php" -mtime -3 -size +10k
For OR logic, use
-o
with parentheses (escaped for the shell):
# Files ending in .log OR .tmp
find /var -type f \( -name "*.log" -o -name "*.tmp" \)
Acting on results
find
can do more than list files. The
-exec
flag runs a command on each result:
# Delete all .tmp files older than 7 days
find /tmp -type f -name "*.tmp" -mtime +7 -exec rm {} \;
# Change permissions on all PHP files
find /var/www -type f -name "*.php" -exec chmod 644 {} \;
The
{}
is a placeholder for each file found, and
\;
marks the end of the command. If you’re running a command on many files,
+
is more efficient than
\;
because it batches the files:
find /var/www -type f -name "*.php" -exec chmod 644 {} +
Searching text with grep#
While
find
locates files by name, type, or metadata,
grep
searches inside files for text patterns. It reads through file contents line by line and prints every line that matches your pattern.
Basic text search
Search a single file for a string:
grep "database" /etc/myapp/config.php
This prints every line in
config.php
that contains the word “database.”
Recursive search
When you don’t know which file contains the text, search an entire directory tree:
grep -r "database_host" /etc/
The
-r
flag tells
grep
to recurse through all files under
/etc/
. This is probably the most common way to use
grep
on a server. Something is referencing a hostname or IP address and you need to find where.
Show only filenames
Sometimes you just want to know which files contain the match, not the matching lines themselves:
grep -rl "old-domain.com" /var/www/
The
-l
flag suppresses the line output and prints only filenames. Useful when you’re planning a find-and-replace across a project and need to see the scope first.
Case-insensitive search
By default,
grep
is case-sensitive. “Error” and “error” are different strings. The
-i
flag makes it ignore case:
grep -ri "error" /var/log/nginx/
This catches “Error,” “ERROR,” “error,” and any other capitalization variant.
Show line numbers
When you need to know where in the file the match occurs:
grep -n "timeout" /etc/nginx/nginx.conf
The
-n
flag prepends each matching line with its line number. Saves you from opening the file and scrolling to find the match.
Count matches
If you just need to know how many times a pattern appears:
grep -c "404" /var/log/nginx/access.log
This outputs a single number: the count of matching lines.
Show context around matches
A matching line by itself isn’t always enough to understand what’s going on. Context flags show surrounding lines:
# 3 lines after each match
grep -A 3 "error" /var/log/app.log
# 3 lines before each match
grep -B 3 "error" /var/log/app.log
# 3 lines before and after
grep -C 3 "error" /var/log/app.log
Regular expressions
Grep supports regular expressions, which let you match patterns rather than literal strings.
# Lines starting with "error"
grep "^error" logfile.log
# Lines ending with a number
grep "[0-9]$" data.txt
# Lines containing an IP address pattern
grep -E "[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}" access.log
The
-E
flag enables extended regex, which supports operators like
|
(OR),
+
(one or more), and
{}
(quantifiers) without needing to escape them.
# Lines containing "error" OR "warning"
grep -E "error|warning" /var/log/syslog
Inverting matches
The
-v
flag returns lines that don’t match the pattern. Useful for filtering out noise:
# Show all log lines except those containing "DEBUG"
grep -v "DEBUG" /var/log/app.log
# Show non-empty lines
grep -v "^$" config.file
Piping into grep
One of grep’s most practical uses is filtering the output of other commands:
# Find a specific process
ps aux | grep nginx
# Find a specific package
rpm -qa | grep php
# Filter file listings
ls -la /etc/ | grep "ssl"
This works because grep reads from standard input when you pipe into it. Any command’s output can be filtered this way.
Combining find and grep#
Individually,
find
and
grep
cover different ground. Together, they handle searches that neither can do alone: finding files that match certain criteria and then searching inside those files for specific text.
Search within found files
Find all PHP files under
/var/www
and search each one for database credentials:
find /var/www -type f -name "*.php" -exec grep -l "db_password" {} +
This returns only the filenames containing “db_password.” Without the combination, you’d either grep through every file (including images, binaries, and other irrelevant files) or manually check each PHP file individually.
Time-based content searches
Find log files modified today and search them for errors:
find /var/log -type f -name "*.log" -mtime -1 -exec grep -H "CRITICAL" {} +
The
-H
flag ensures grep prints the filename alongside each match, so you know which log file the error came from.
Complex pattern matching
Find config files and search for lines referencing either a staging or production database:
find /etc -type f -name "*.conf" -exec grep -HnE "(staging|production)_db" {} +
This combines find’s file-location ability with grep’s regex support and line numbering. The output tells you exactly which file, which line number, and which database reference was found.
An alternative: grep -r with –include
For simpler cases, you can skip
find
entirely and use grep’s built-in file filtering:
grep -rn --include="*.php" "db_password" /var/www/
The
--include
flag limits the recursive search to files matching the pattern. This is often faster to type than a full
find
/
grep
combination, though
find
gives you more filtering options (size, time, owner) that grep can’t match.
Other useful search commands#
locate: fast filename searches
The
locate
command searches a pre-built database of filenames, making it much faster than
find
for simple name lookups:
locate nginx.conf
The database is updated periodically by a cron job running
updatedb
. This means recently created files might not appear in results until the database is refreshed. Run
sudo updatedb
manually if you need current results.
whereis: finding binaries and documentation
whereis
locates the binary, source code, and manual page for a command:
whereis nginx
# nginx: /usr/sbin/nginx /etc/nginx /usr/share/nginx /usr/share/man/man8/nginx.8.gz
Useful when you need to know where a program is installed, especially when multiple versions might exist on the system.
which: finding the active binary
which
tells you exactly which executable runs when you type a command:
which python3
# /usr/bin/python3
This resolves your PATH and shows the first match. Handy when you have multiple versions installed and need to confirm which one is being used.
Quick reference#
| Task | Command |
|---|---|
| Find file by name |
find /path -name "filename"
|
| Find files by extension |
find /path -type f -name "*.ext"
|
| Find recently modified files |
find /path -type f -mtime -1
|
| Find large files |
find /path -type f -size +100M
|
| Search file contents |
grep "pattern" filename
|
| Recursive text search |
grep -r "pattern" /path/
|
| Case-insensitive search |
grep -ri "pattern" /path/
|
| Show filenames only |
grep -rl "pattern" /path/
|
| Find files then search contents |
find /path -name "*.ext" -exec grep -l "pattern" {} +
|
| Filter command output |
command | grep "pattern"
|
Check out the GNU Coreutils documentation and the grep manual for the complete reference.
Manage your servers with confidence. Try Hostney web hosting free for 14 days.