find - Search for Files and Directories

Powerful recursive file system search utility

Command Overview

The find command is one of the most powerful and versatile utilities in Linux/Unix. It recursively searches directory trees for files and directories that match specified criteria, and can execute commands on the results. It's an essential tool for system administration, file management, and automation.

Basic Syntax

find [path...] [expression]

Where:

  • path - Starting directory (defaults to current directory if omitted)
  • expression - Tests, actions, and options that define what to find and what to do

Common Test Operators

Option Description Example
-name pattern File name matches pattern (case-sensitive) -name "*.txt"
-iname pattern File name matches pattern (case-insensitive) -iname "*.TXT"
-type c File type (f=file, d=directory, l=link) -type f
-size n File size (+ greater, - less, no prefix exact) -size +100M
-mtime n Modified n days ago -mtime -7
-user name Owned by user -user root
-perm mode File permissions match -perm 644
-empty Empty files or directories -empty

Detailed Examples

Example 1

Basic File Search by Name

Finding files with specific names or patterns:

# Find all .conf files in /etc
$ find /etc -name "*.conf"
/etc/ssh/sshd_config
/etc/systemd/system.conf
/etc/rsyslog.conf

# Find specific file regardless of location
$ find /var -name "access.log"
/var/log/apache2/access.log
/var/log/nginx/access.log

# Case-insensitive search
$ find /home -iname "readme.txt"
/home/user/README.txt
/home/user/projects/ReadMe.TXT
/home/user/documents/readme.txt

Explanation: The -name option performs case-sensitive pattern matching using shell wildcards (* and ?). Use -iname for case-insensitive searches. Always quote patterns to prevent shell expansion.

Tip: When searching system directories like /etc or /var, you may need sudo privileges to access all subdirectories.
Example 2

Finding Files by Type and Size

Locating files based on type and size criteria:

# Find all directories in current location
$ find . -type d
./documents
./documents/projects
./downloads

# Find files larger than 100MB
$ find /home/user -type f -size +100M
/home/user/videos/movie.mp4
/home/user/downloads/ubuntu.iso

# Find files smaller than 1KB (likely empty or minimal)
$ find /tmp -type f -size -1k
/tmp/test.txt
/tmp/.hidden

# Find files exactly 0 bytes (empty files)
$ find /var/log -type f -size 0
/var/log/empty.log

# Find files between 10MB and 50MB
$ find /home -type f -size +10M -size -50M

Explanation: Size can be specified in blocks (b), kilobytes (k), megabytes (M), or gigabytes (G). The + prefix means "greater than," - means "less than," and no prefix means "exactly."

Note: Size specifications: c=bytes, k=kilobytes, M=megabytes, G=gigabytes. The default (no suffix) is 512-byte blocks.
Example 3

Time-Based Searches

Finding files based on modification, access, or change times:

# Find files modified in last 7 days
$ find /home/user/documents -type f -mtime -7
/home/user/documents/report.pdf
/home/user/documents/notes.txt

# Find files modified exactly 30 days ago
$ find /var/log -name "*.log" -mtime 30

# Find files NOT modified in last 90 days (candidates for archival)
$ find /backup -type f -mtime +90

# Find files accessed in last 24 hours
$ find /var/www -type f -atime -1

# Find files changed (metadata) in last hour
$ find /etc -cmin -60

# Find files modified in last 2 hours
$ find /tmp -type f -mmin -120

Explanation: Time options: -mtime (modified), -atime (accessed), -ctime (changed). Units in days for -time options, minutes for -min options. Negative values mean "within last N," positive means "exactly N ago."

Tip: Use -mtime -1 for files modified in the last 24 hours, or -mmin -60 for the last hour. This is useful for tracking recent changes or finding log files with recent activity.
Example 4

Permission and Ownership Searches

Finding files based on permissions and ownership:

# Find files with specific permissions (exact match)
$ find /var/www -type f -perm 0644
/var/www/html/index.html
/var/www/html/style.css

# Find files that are world-writable (security risk)
$ find / -type f -perm -0002 2>/dev/null
/tmp/shared_file
/var/tmp/public_writable

# Find setuid files (potential security concern)
$ find / -type f -perm -4000 -ls 2>/dev/null
/usr/bin/passwd
/usr/bin/sudo

# Find files owned by specific user
$ find /home -user john -type f
/home/john/.bashrc
/home/john/documents/file.txt

# Find files owned by specific group
$ find /var/www -group www-data

# Find files with no valid owner (orphaned)
$ find / -nouser -o -nogroup 2>/dev/null

Explanation: Permission searches can use exact matches (0644) or symbolic modes. The -perm -mode finds files with at least those permission bits set. Finding setuid/setgid files is important for security audits.

Security Warning: World-writable files and setuid binaries can be security risks. Regularly audit these with find and verify they're intentional.
Example 5

Combining Multiple Conditions

Using logical operators to create complex searches:

# Find .txt OR .log files
$ find /var/log -name "*.txt" -o -name "*.log"

# Find .conf files modified in last 7 days (AND condition - implicit)
$ find /etc -name "*.conf" -mtime -7
/etc/ssh/sshd_config
/etc/nginx/nginx.conf

# Find large log files modified recently
$ find /var/log -name "*.log" -size +50M -mtime -30

# Find files that are NOT .txt files
$ find /home/user/documents -type f ! -name "*.txt"

# Find empty directories or files
$ find /tmp \( -type f -o -type d \) -empty

# Complex: Find .sh files that are executable by owner
$ find /usr/local/bin -name "*.sh" -perm -u+x

# Find files owned by user john that are larger than 100M
$ find /home -user john -size +100M -type f

Explanation: Operators: -a or AND (implicit between tests), -o for OR, ! for NOT. Use parentheses \( \) to group conditions. Without explicit operators, conditions are ANDed together.

Note: Parentheses must be escaped with backslashes in the shell: \( and \)
Example 6

Executing Commands on Found Files

Using -exec and -execdir to perform actions on search results:

# Delete all .tmp files
$ find /tmp -name "*.tmp" -type f -exec rm {} \;

# More efficient deletion using +
$ find /tmp -name "*.tmp" -type f -exec rm {} +

# Change ownership of all .log files
$ find /var/log -name "*.log" -exec chown syslog:adm {} \;

# Change permissions on all directories
$ find /var/www -type d -exec chmod 755 {} \;

# Copy all .conf files to backup directory
$ find /etc -name "*.conf" -exec cp {} /backup/configs/ \;

# Find and display detailed info for large files
$ find /home -size +500M -exec ls -lh {} \;

# Search for text in all .log files
$ find /var/log -name "*.log" -exec grep -l "error" {} \;

# Compress old log files
$ find /var/log -name "*.log" -mtime +30 -exec gzip {} \;

Explanation: The -exec action runs a command on each found file. {} is replaced with the file name. \; ends the command and runs it once per file. Using + instead of \; passes multiple files to one command invocation (more efficient).

Warning: Be extremely careful with -exec rm. Test your find command first with -print before using destructive actions.
Example 7

Finding and Managing Duplicate Files

Locating duplicate files based on size and checksums:

# Find files with same size (potential duplicates)
$ find /home/user -type f -exec ls -l {} \; | awk '{print $5, $9}' | sort -n

# Find duplicate files by MD5 sum (more thorough)
$ find /home/user/photos -type f -exec md5sum {} \; | sort | uniq -w32 -d

# Find and list duplicate files with their paths
$ find . -type f -exec md5sum {} + | sort | uniq -w32 -d --all-repeated=separate

# Script to find and report duplicates
$ find /data -type f -printf '%s\n' | sort -n | uniq -d | while read size; do
    find /data -type f -size ${size}c -exec md5sum {} \;
done | sort | uniq -w32 -d

# Find files with exactly the same name in different directories
$ find /home -type f | awk -F/ '{print $NF}' | sort | uniq -d

Explanation: Finding duplicates typically involves first grouping by size (fast), then comparing checksums (slower but accurate). MD5 or SHA checksums identify identical content even with different names.

Tip: For large directories, first filter by size to reduce the number of files that need checksum calculation. Use tools like fdupes for more sophisticated duplicate detection.
Example 8

System Maintenance and Cleanup Tasks

Using find for routine system administration:

# Find and delete core dumps older than 7 days
$ find /var/crash -name "core.*" -mtime +7 -delete

# Find large log files and rotate them
$ find /var/log -name "*.log" -size +100M -exec logrotate -f {} \;

# Clean up old temporary files
$ find /tmp -type f -atime +30 -user nobody -delete

# Find broken symbolic links
$ find /usr/local -type l ! -exec test -e {} \; -print
/usr/local/bin/old_script
/usr/local/lib/broken_link.so

# Remove broken symlinks
$ find /home -xtype l -delete

# Find files without valid owner (after user deletion)
$ find / -nouser -print 2>/dev/null

# Archive old log files
$ find /var/log -name "*.log" -mtime +60 -exec tar -czf archived-logs.tar.gz {} +

# Find and remove empty directories
$ find /var/tmp -type d -empty -delete

Explanation: The -delete action is safer than -exec rm as it has built-in protections. -xtype l finds broken symbolic links. Regular maintenance tasks using find can be scheduled with cron.

Note: Always test find commands with -print before using -delete or destructive actions. Consider using -maxdepth to limit search depth for performance.
Example 9

Advanced Pattern Matching and Exclusions

Complex file searches with includes and excludes:

# Find all Python files except in __pycache__ directories
$ find /project -name "*.py" ! -path "*/__pycache__/*"

# Find files excluding multiple directories
$ find /home -name "*.txt" \
    ! -path "*/node_modules/*" \
    ! -path "*/.git/*" \
    ! -path "*/vendor/*"

# Find recently modified source files, excluding build directories
$ find /project -name "*.c" -o -name "*.h" \
    ! -path "*/build/*" \
    ! -path "*/dist/*" \
    -mtime -7

# Search only within specific depth
$ find /var -maxdepth 2 -name "*.conf"
/var/cache/app.conf
/var/lib/service.conf

# Find files with multiple extensions
$ find . -type f \( -name "*.jpg" -o -name "*.png" -o -name "*.gif" \)

# Regex pattern matching
$ find /etc -regextype posix-extended -regex ".*/[a-z]+\.conf$"

# Case-insensitive regex
$ find /var/log -regextype posix-extended -iregex ".*error.*\.log$"

Explanation: Use ! -path to exclude directories. -maxdepth limits recursion depth. -regex provides more powerful pattern matching than -name. Combine multiple patterns with -o (OR).

Tip: When excluding directories like .git, node_modules, or build directories, place the exclusion early in the expression for better performance.
Example 10

Performance Optimization and Best Practices

Optimizing find for speed and efficiency:

# Limit search to filesystem boundaries (don't cross mount points)
$ find /home -xdev -name "*.log"

# Stop after finding first match
$ find /etc -name "nginx.conf" -quit
/etc/nginx/nginx.conf

# Parallel execution for better performance on large searches
$ find /data -name "*.txt" -print0 | xargs -0 -P 4 -I {} grep "pattern" {}

# Prune directories to avoid searching them
$ find /var -type d -name "cache" -prune -o -name "*.log" -print

# Use -printf for custom output formatting
$ find /home -name "*.pdf" -printf "%p\t%s\t%TY-%Tm-%Td\n"
/home/user/doc.pdf    1048576    2025-01-15

# Find with null-terminated output (safe for filenames with spaces)
$ find /data -name "*.txt" -print0 | xargs -0 wc -l

# Optimize with -O flag (optimization level 1-3)
$ find -O3 /large/directory -name "*.dat"

# Show find command performance statistics
$ time find /usr -name "python*"

# Use locate for faster searches when appropriate
$ updatedb
$ locate nginx.conf  # Much faster than find for indexed searches

Explanation: -xdev prevents crossing filesystem boundaries (useful for avoiding network mounts). -prune excludes directories from search. -print0 with xargs -0 handles filenames with spaces safely. For frequently searched patterns, consider using locate instead.

Performance Note: For very large filesystems, consider using locate (requires updatedb), or specialized tools like fd or ripgrep which can be significantly faster for certain use cases.

Common Options Reference

Option Description
-name pattern Base of file name matches shell pattern
-iname pattern Like -name but case-insensitive
-type c File type: f(file), d(dir), l(link), c(char), b(block), p(pipe), s(socket)
-size [+/-]n[cwbkMG] File uses n units of space
-mtime [+/-]n File modified n*24 hours ago
-atime [+/-]n File accessed n*24 hours ago
-ctime [+/-]n File status changed n*24 hours ago
-mmin [+/-]n File modified n minutes ago
-user name File owned by user name or UID
-group name File belongs to group name or GID
-perm mode File permission bits match mode
-empty File is empty and is regular file or directory
-maxdepth n Descend at most n levels below start point
-mindepth n Do not apply tests at levels less than n
-exec cmd {} \; Execute command on each file
-delete Delete found files
-print Print full file name (default)
-print0 Print with null separator (for xargs -0)

Important Best Practices

Best Practices

  • Always test find commands with -print before using destructive actions
  • Use -print0 with xargs -0 for files with spaces or special characters
  • Quote patterns to prevent shell expansion: "*.txt" not *.txt
  • Use -maxdepth to limit search scope and improve performance
  • Redirect stderr with 2>/dev/null when searching system directories without root
  • Consider -xdev to avoid crossing filesystem boundaries
  • Use -prune to exclude large directories from search
  • Combine with xargs or -exec {} + for efficient batch operations

Common Pitfalls

  • Unquoted wildcards: Shell expands them before find sees them
  • Permission denied: Use sudo for system directories or redirect stderr
  • Slow searches: Use -maxdepth, -xdev, or -prune to optimize
  • Space in filenames: Use -print0 with xargs -0 for safe handling
  • Logic errors: Remember AND is implicit; use -o for OR explicitly
  • Destructive actions: Always verify with -print first

Alternative Tools

Consider these faster alternatives for specific use cases:

  • locate/mlocate: Much faster for name searches, but requires updatedb
  • fd: Modern, user-friendly alternative with sensible defaults
  • ripgrep (rg): Extremely fast content search
  • tree: Visual directory structure display