Skip to content

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? which shows you the first match. type -a shows every match across your entire $PATH — critical when you have multiple versions installed.

    Finding Executable Locations
    which 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 install
    

    Key insight: If which returns nothing, the command isn't in your $PATH. It might be installed but not on your PATH, or not installed at all. Use find next.

  • locate — Fast Name Search


    Why it matters: locate searches a pre-built index instead of crawling the filesystem live. It's orders of magnitude faster than find for interactive name searches.

    Using locate
    locate nginx.conf
    # /etc/nginx/nginx.conf
    # /usr/share/doc/nginx/examples/nginx.conf
    
    locate -i readme   # -i makes it case-insensitive
    

    Key insight: locate can be stale — it won't find files created since the last database update. Run sudo updatedb to refresh it. On many systems this runs nightly via cron, but on new servers or fresh installs it may never have run.

    Update locate Database
    sudo updatedb       # refresh the database
    locate myapp.conf   # now it will find newly created files
    
  • find — Flexible Filesystem Search


    Why it matters: find walks the filesystem live. It's slower than locate but can search by name, type, size, age, owner, permissions, or any combination. Indispensable for scripts because it's always accurate.

    find Basics
    find /etc -name "nginx.conf"
    # /etc/nginx/nginx.conf
    
    find /var/log -name "*.log" -type f
    # finds only files (not dirs) named *.log under /var/log
    
    find / -name "hosts" 2>/dev/null    # (1)!
    # /etc/hosts
    # /var/lib/docker/containers/.../hosts
    
    1. 2>/dev/null silences "Permission denied" errors for directories you can't read. The 2> redirects stderr (file descriptor 2) to /dev/null (the discard device), keeping stdout clean.

    Key insight: find is the right tool for scripts. locate is fast but can return stale results. In automation, always use find.

  • grep -r — Search by Content


    Why it matters: Sometimes you know what's inside a file but not the filename. grep -r searches file contents recursively.

    Searching File Contents
    grep -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
    
    1. -r searches recursively. -l shows only filenames, not the matching lines — useful when you want to know which files contain a pattern, not the lines themselves.

    Key insight: grep -r is for content; find is 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

Name-Based Searches
find /etc -name "*.conf"            # files ending in .conf
find /etc -name "nginx*"            # files starting with nginx
find /etc -iname "Nginx.conf"       # -iname is case-insensitive
find / -name "authorized_keys" 2>/dev/null   # find SSH auth keys anywhere

Filtering by Type

Type-Based Searches
find /var/log -type f       # files only (not directories)
find /etc -type d           # directories only
find /usr/bin -type l       # symbolic links only

Filtering by Size

Size-Based Searches
find / -type f -size +100M 2>/dev/null     # files larger than 100MB
find /var -type f -size +10M 2>/dev/null   # files in /var larger than 10MB
find /tmp -type f -size -1k                # 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

Age-Based Searches
find /var/log -name "*.log" -mtime -7      # modified in the last 7 days
find /tmp -type f -mtime +30               # not modified in 30+ days
find /etc -newer /etc/hosts                # modified more recently than /etc/hosts
find /var/log -name "*.log" -mmin -60      # 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

Owner and Permission Searches
find /home -user jsmith             # files owned by jsmith
find /var/www -group www-data       # files owned by www-data group
find / -perm -4000 2>/dev/null      # SUID files (potential security concern)
find / -perm -002 2>/dev/null       # world-writable files

Combining Filters

Filters combine with implicit AND by default. Use -o for OR and ! for NOT:

Combining Filters
# Files in /var/log, larger than 10MB, modified in the last week
find /var/log -type f -size +10M -mtime -7

# Config files OR certificate files in /etc
find /etc -name "*.conf" -o -name "*.crt"

# Files in /tmp not owned by root
find /tmp -type f ! -user 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

Using -exec
# View every .conf file found
find /etc -name "*.conf" -exec cat {} \;    # (1)!

# Check permissions on found files
find /var/www -type f -exec ls -lh {} \;

# Delete files older than 30 days in /tmp
find /tmp -type f -mtime +30 -exec rm {} \;
  1. {} is replaced by the filename for each result. The \; ends the -exec expression. The backslash escapes the semicolon from shell interpretation.

Efficiency note: -exec command {} \; runs the command once per file. For large result sets, use + instead — it passes all results at once:

-exec with + (More Efficient)
# Runs: ls -lh file1 file2 file3 ...  (one invocation)
find /etc -name "*.conf" -exec ls -lh {} +

xargs: Pipe Results to Another Command

xargs takes input from stdin and passes it as arguments to a command:

Using xargs
find /etc -name "*.conf" | xargs grep "listen"
# searches all .conf files for "listen"

find /var/log -name "*.log" -mtime +30 | xargs ls -lh
# list details of all old log files

Handling filenames with spaces: The default behavior breaks on spaces. Use -print0 and xargs -0 for safety:

Safe xargs with Spaces in Filenames
find /home -type f -name "*.txt" -print0 | xargs -0 grep "password"
# -print0 uses null bytes as delimiters instead of newlines
# xargs -0 reads 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.

Hunting Config Files
# 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.

Finding Large Files
# Files over 100MB anywhere on the filesystem
find / -type f -size +100M 2>/dev/null | xargs ls -lh | sort -k5 -hr

# In /var specifically (where most growth happens)
find /var -type f -size +50M 2>/dev/null

# Recently modified large files (a growing problem)
find /var -type f -size +10M -mtime -1 2>/dev/null

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.

Finding Recent Changes
# Files changed in the last 24 hours in /etc
find /etc -type f -mtime -1

# Files changed in the last hour across key dirs
find /etc /var/lib /opt -type f -mmin -60 2>/dev/null

# Files newer than a reference file (useful after incidents)
find /etc -newer /etc/hosts -type f    # changed after /etc/hosts was 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.

Finding Files by Owner
# All files owned by a specific user
find /home /var /opt -user jsmith 2>/dev/null

# Files with no valid owner (user was deleted)
find / -nouser 2>/dev/null | head -20

# Files owned by root in a directory that shouldn't have them
find /home -user root -type f 2>/dev/null

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
Finding sshd_config
find /etc -name "sshd_config"
# /etc/ssh/sshd_config

Or with locate for speed:

Using locate
locate sshd_config
# /etc/ssh/sshd_config
# /usr/share/doc/openssh/examples/sshd_config

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
Finding Large Files in /var
find /var -type f -size +50M 2>/dev/null -exec ls -lh {} \; | sort -k5 -hr

Or with xargs (more efficient for large result sets):

Using xargs for Large File Listing
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
Finding Recent Changes in /etc
find /etc -type f -mtime -1

If the change happened within the last hour:

Very Recent Changes
find /etc -type f -mmin -60

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
Finding Files by Deleted User
# If the username still resolves (user in /etc/passwd but shell removed)
find /home /var /opt -user olddev 2>/dev/null

# If the user was fully deleted, their files show a numeric UID
find /home /var /opt -nouser 2>/dev/null

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; use type -a to find all versions
  • locate — fast name search against a pre-built database; may be stale, run sudo updatedb to refresh
  • find — live filesystem search; the right tool for scripts and precise searches
  • find filters: -name, -type, -size, -mtime, -user, -group, -nouser
  • Acting on results: -exec command {} \; for one-at-a-time, -exec command {} + for batch, | xargs for piping
  • Silence permission errors with 2>/dev/null — you'll use this constantly

Further Reading

Command References

  • man find — the complete find manual; extensive and worth reading
  • man locate — locate options and database management
  • man xargs — full xargs documentation, including parallel execution with -P
  • man updatedb — how the locate database is built and configured

Deep Dives

Official Documentation


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.