Finding Files🔗
Part of Essentials
This article assumes familiarity with the Filesystem Hierarchy. Knowing where things should be makes finding them much faster.
You've just been handed access to a server you've never seen before. There's an application running — you need to find its config file. Or maybe disk space is critically low and you need to find what's eating it. Or a log file rotated and you're not sure where the compressed version ended up.
These are daily situations for sysadmins and DevOps engineers. The difference between 30 seconds and 30 minutes is knowing which tool to reach for.
Where You've Seen This🔗
On Windows, you'd use File Explorer's search or the where command for executables. In your IDE, it's Ctrl+Shift+F (find in files). Those work on a single machine with a GUI. On Linux servers — often headless, often under load, often in the middle of an incident — you need tools that work fast from the command line and compose into scripts.
find in particular shows up everywhere: deployment scripts, cron jobs, log rotation configs, CI pipelines. Learning it interactively is also learning the tool you'll write in automation. The patterns transfer directly.
Why Speed Matters Here
When something breaks in production, finding the right config or log file fast isn't a convenience — it's the job. find /etc -name "*.conf" -mtime -1 tells you everything that changed in configuration in the last 24 hours in seconds. Knowing find cold is one of the clearest separators between engineers who thrive in Linux environments and those who struggle.
Choosing the Right Tool🔗
graph TD
A[What are you looking for?] --> B{Is it an executable\nor command?}
B -->|Yes| C["which / type -a\nFinds binaries in PATH"]
B -->|No| D{Do you know\nthe file name?}
D -->|Yes, need speed| E["locate\nSearches a pre-built database"]
D -->|Yes, need precision| F["find -name\nLive filesystem search"]
D -->|No, but know other traits| G["find with filters\n-size, -mtime, -user, -type"]
D -->|No, but know the contents| H["grep -r\nSearch inside files"]
H --> I["See: grep article"]
style A fill:#d69e2e,stroke:#cbd5e0,stroke-width:2px,color:#000
style C fill:#2d3748,stroke:#68d391,stroke-width:2px,color:#fff
style E fill:#2d3748,stroke:#63b3ed,stroke-width:2px,color:#fff
style F fill:#2d3748,stroke:#fc8181,stroke-width:2px,color:#fff
style G fill:#2d3748,stroke:#fc8181,stroke-width:2px,color:#fff
style H fill:#2d3748,stroke:#718096,stroke-width:2px,color:#fff
style I fill:#1a202c,stroke:#718096,stroke-width:1px,color:#9ca3af
The Tools🔗
-
which / type -a — Finding Executables
Why it matters: When you run
nginx, what binary actually runs?whichshows you the first match.type -ashows every match across your entire$PATH— critical when you have multiple versions installed.Finding Executable Locationswhich nginx # /usr/sbin/nginx which python3 # /usr/bin/python3 type -a python3 # python3 is /usr/bin/python3 # python3 is /usr/local/bin/python3 ← virtualenv or custom installKey insight: If
whichreturns nothing, the command isn't in your$PATH. It might be installed but not on your PATH, or not installed at all. Usefindnext. -
locate — Fast Name Search
Why it matters:
locatesearches a pre-built index instead of crawling the filesystem live. It's orders of magnitude faster thanfindfor interactive name searches.Using locatelocate nginx.conf # /etc/nginx/nginx.conf # /usr/share/doc/nginx/examples/nginx.conf locate -i readme # (1)!-imakes it case-insensitive.
Key insight:
locatecan be stale — it won't find files created since the last database update. Runsudo updatedbto refresh it. On many systems this runs nightly via cron, but on new servers or fresh installs it may never have run.- refresh the database.
- now it will find newly created files.
-
find — Flexible Filesystem Search
Why it matters:
findwalks the filesystem live. It's slower thanlocatebut can search by name, type, size, age, owner, permissions, or any combination. Indispensable for scripts because it's always accurate.find Basicsfind /etc -name "nginx.conf" # /etc/nginx/nginx.conf find /var/log -name "*.log" -type f # (1)! find / -name "hosts" 2>/dev/null # (2)! # /etc/hosts # /var/lib/docker/containers/.../hosts- finds only files (not dirs) named
*.logunder/var/log. 2>/dev/nullsilences "Permission denied" errors for directories you can't read. The2>redirects stderr (file descriptor 2) to/dev/null(the discard device), keeping stdout clean.
Key insight:
findis the right tool for scripts.locateis fast but can return stale results. In automation, always usefind. - finds only files (not dirs) named
-
grep -r — Search by Content
Why it matters: Sometimes you know what's inside a file but not the filename.
grep -rsearches file contents recursively.Searching File Contentsgrep -r "database_host" /etc/myapp/ # /etc/myapp/config.yml: database_host: db-prod-01 grep -rl "FAILED" /var/log/ # (1)! # /var/log/auth.log # /var/log/application/app.log-rsearches recursively.-lshows only filenames, not the matching lines — useful when you want to know which files contain a pattern, not the lines themselves.
Key insight:
grep -ris for content;findis for file attributes. See the grep article for the full story on searching inside files.
Mastering find🔗
find has a reputation for being intimidating. The syntax is unusual, but the pattern is consistent: find [where] [what criteria] [what to do].
Once you internalize the common filters, you'll reach for find constantly.
Filtering by Name🔗
find /etc -name "*.conf" # (1)!
find /etc -name "nginx*" # (2)!
find /etc -iname "Nginx.conf" # (3)!
find / -name "authorized_keys" 2>/dev/null # (4)!
- files ending in
.conf. - files starting with
nginx. -inameis case-insensitive.- find SSH auth keys anywhere.
Filtering by Type🔗
find /var/log -type f # (1)!
find /etc -type d # (2)!
find /usr/bin -type l # (3)!
- files only (not directories).
- directories only.
- symbolic links only.
Filtering by Size🔗
find / -type f -size +100M 2>/dev/null # (1)!
find /var -type f -size +10M 2>/dev/null # (2)!
find /tmp -type f -size -1k # (3)!
- files larger than 100MB.
- files in
/varlarger than 10MB. - files smaller than 1KB.
Size units: c (bytes), k (kilobytes), M (megabytes), G (gigabytes). Prefix with + for "greater than", - for "less than".
Filtering by Age🔗
find /var/log -name "*.log" -mtime -7 # (1)!
find /tmp -type f -mtime +30 # (2)!
find /etc -newer /etc/hosts # (3)!
find /var/log -name "*.log" -mmin -60 # (4)!
- modified in the last 7 days.
- not modified in 30+ days.
- modified more recently than
/etc/hosts. - modified in the last 60 minutes.
-mtime counts in days. -mmin counts in minutes. +N means "older than N", -N means "newer than N" (confusingly, but consistently).
Filtering by Owner and Permissions🔗
find /home -user jsmith # (1)!
find /var/www -group www-data # (2)!
find / -perm -4000 2>/dev/null # (3)!
find / -perm -002 2>/dev/null # (4)!
- files owned by jsmith.
- files owned by www-data group.
- SUID files (potential security concern).
- world-writable files.
Combining Filters🔗
Filters combine with implicit AND by default. Use -o for OR and ! for NOT:
find /var/log -type f -size +10M -mtime -7 # (1)!
find /etc -name "*.conf" -o -name "*.crt" # (2)!
find /tmp -type f ! -user root # (3)!
- Files in
/var/log, larger than 10MB, modified in the last week. - Config files OR certificate files in
/etc. - Files in
/tmpnot owned by root.
Acting on Results: -exec and xargs🔗
Finding files is only half the job. Often you need to do something with them.
-exec: Run a Command on Each Result🔗
find /etc -name "*.conf" -exec cat {} \; # (1)!
find /var/www -type f -exec ls -lh {} \; # (2)!
find /tmp -type f -mtime +30 -exec rm {} \; # (3)!
- View every
.conffile found.{}is replaced by the filename for each result;\;ends the-execexpression (the backslash escapes the semicolon from shell interpretation). - Check permissions on found files.
- Delete files older than 30 days in
/tmp.
Efficiency note: -exec command {} \; runs the command once per file. For large result sets, use + instead — it passes all results at once:
- Runs
ls -lh file1 file2 file3 ...as a single invocation.
xargs: Pipe Results to Another Command🔗
xargs takes input from stdin and passes it as arguments to a command:
find /etc -name "*.conf" | xargs grep "listen" # (1)!
find /var/log -name "*.log" -mtime +30 | xargs ls -lh # (2)!
- searches all
.conffiles for "listen". - list details of all old log files.
Handling filenames with spaces: The default behavior breaks on spaces. Use -print0 and xargs -0 for safety:
find /home -type f -name "*.txt" -print0 | xargs -0 grep "password" # (1)!
-print0uses null bytes as delimiters instead of newlines;xargs -0reads that null-delimited input.
This is a best practice in scripts. For interactive use, the simple pipe is usually fine.
Common Real-World Patterns🔗
You know a service is configured somewhere but don't know the exact path.
# By service name (usually works)
find /etc -name "*nginx*" -type f
find /etc -name "*postgresql*" -type f
# By extension
find /etc -name "*.conf" -type f | grep -i myapp
find /etc -name "*.yml" -o -name "*.yaml" | xargs grep -l "myapp" 2>/dev/null
# Service unit files often point to the config
systemctl cat myapp.service | grep -i "config\|conf\|env"
Pattern: Start with the service name. If that fails, look for the config in the unit file — it usually references the path directly.
Disk is full. Need to find what's consuming space fast.
find / -type f -size +100M 2>/dev/null | xargs ls -lh | sort -k5 -hr # (1)!
find /var -type f -size +50M 2>/dev/null # (2)!
find /var -type f -size +10M -mtime -1 2>/dev/null # (3)!
- Files over 100MB anywhere on the filesystem.
- In
/varspecifically (where most growth happens). - Recently modified large files (a growing problem).
Pattern: Combine du -sh /var/* | sort -hr | head -10 (from the Filesystem Hierarchy article) to find which directory is growing, then drill in with find -size.
Something broke recently. You want to know what changed.
find /etc -type f -mtime -1 # (1)!
find /etc /var/lib /opt -type f -mmin -60 2>/dev/null # (2)!
find /etc -newer /etc/hosts -type f # (3)!
- Files changed in the last 24 hours in
/etc. - Files changed in the last hour across key dirs.
- Files newer than a reference file (useful after incidents) — changed after
/etc/hostswas last modified.
Pattern: Set a reference point first — touch /tmp/checkpoint — then later run find / -newer /tmp/checkpoint to see everything that changed since.
Auditing user files, or tracking down orphaned files after a user was removed.
find /home /var /opt -user jsmith 2>/dev/null # (1)!
find / -nouser 2>/dev/null | head -20 # (2)!
find /home -user root -type f 2>/dev/null # (3)!
- All files owned by a specific user.
- Files with no valid owner (user was deleted).
- Files owned by root in a directory that shouldn't have them.
Quick Reference🔗
Tool Selection🔗
| Tool | Speed | Accuracy | Best For |
|---|---|---|---|
which |
Instant | Always current | Finding executables in $PATH |
type -a |
Instant | Always current | Finding all versions of an executable |
locate |
Very fast | May be stale | Interactive name search |
find |
Moderate | Always current | Scripts, precise searches, multiple criteria |
find Filter Cheatsheet🔗
| Filter | Example | What It Matches |
|---|---|---|
-name |
-name "*.conf" |
Files matching the pattern (case-sensitive) |
-iname |
-iname "*.Conf" |
Case-insensitive name match |
-type f |
-type f |
Regular files only |
-type d |
-type d |
Directories only |
-type l |
-type l |
Symbolic links only |
-size +N |
-size +100M |
Larger than N |
-size -N |
-size -1k |
Smaller than N |
-mtime -N |
-mtime -7 |
Modified in last N days |
-mtime +N |
-mtime +30 |
Not modified in N+ days |
-mmin -N |
-mmin -60 |
Modified in last N minutes |
-user |
-user jsmith |
Owned by user |
-group |
-group www-data |
Owned by group |
-nouser |
-nouser |
No valid owner (deleted user) |
2>/dev/null |
(end of command) | Suppress permission errors |
Practice Exercises🔗
Exercise 1: Find a Known File
Find the SSH server configuration file on the system. You know it's named sshd_config but not the exact path.
Solution
Or with locate for speed:
Note that locate may return documentation copies too — find is more precise when you know the directory to start from.
Exercise 2: Disk Space Investigation
Find all files larger than 50MB in /var. List them with human-readable sizes, sorted largest first.
Solution
find /var -type f -size +50M 2>/dev/null -exec ls -lh {} \; | sort -k5 -hr
Or with xargs (more efficient for large result sets):
find /var -type f -size +50M 2>/dev/null | xargs ls -lh 2>/dev/null | sort -k5 -hr
-k5 sorts by the 5th field of ls -lh output, which is the file size. -h sorts human-readable sizes correctly. -r reverses to largest first.
Exercise 3: Recent Changes Audit
Something changed in /etc in the last 24 hours and a service is now broken. Find all files modified recently so you know what to investigate.
Solution
If the change happened within the last hour:
Once you find the file, check what changed with diff or look at git history if the team uses version control for configs (many do in production environments).
Exercise 4: Orphaned Files
A user olddev was removed from the system. Find all files they left behind under /home, /var, and /opt.
Solution
find /home /var /opt -user olddev 2>/dev/null # (1)!
find /home /var /opt -nouser 2>/dev/null # (2)!
- If the username still resolves (user in
/etc/passwdbut shell removed). - If the user was fully deleted, their files show a numeric UID.
Files owned by a deleted user appear as a numeric UID in ls -l output (e.g., 1042 instead of olddev). -nouser catches these orphaned files.
Quick Recap🔗
which— find a binary in$PATH; usetype -ato find all versionslocate— fast name search against a pre-built database; may be stale, runsudo updatedbto refreshfind— live filesystem search; the right tool for scripts and precise searchesfindfilters:-name,-type,-size,-mtime,-user,-group,-nouser- Acting on results:
-exec command {} \;for one-at-a-time,-exec command {} +for batch,| xargsfor piping - Silence permission errors with
2>/dev/null— you'll use this constantly
Further Reading🔗
Command References🔗
man find— the completefindmanual; extensive and worth readingman locate— locate options and database managementman xargs— full xargs documentation, including parallel execution with-Pman updatedb— how the locate database is built and configured
Deep Dives🔗
- GNU findutils Manual — the authoritative
findreference - The Art of Command Line: Data Wrangling — practical find and xargs patterns
- Brendan Gregg: Linux Performance — includes disk analysis using find
Official Documentation🔗
- Red Hat: Finding Files — RHEL guide to find and locate
- The Linux Documentation Project — Linux HOWTOs and guides
What's Next?🔗
You can now find any file on the system. The next skill is knowing how to get help when you encounter a command you've never seen before.
Head to Finding Help to learn how to read man pages effectively, use --help flags, find information online, and extract what you need from documentation without reading every word.