skip to content

find β€” File Search

POSIX file finder with powerful expression-based filters for name, type, size, time, permissions, and ownership. Covers exec actions, pruning, and real-world recipes.

4 min read 13 snippets 2d ago intermediate

find β€” File Search#

Syntax#

find [PATH...] [EXPRESSION]

Name and path filters#

find . -name "*.log"             # glob match on filename
find . -iname "readme*"          # case-insensitive
find . -path "*/src/*.ts"        # match full path
find . -not -name "*.min.js"     # exclude pattern
find . -name "*.py" -o -name "*.rb"   # OR: .py or .rb

Type filters#

FlagType
-type fregular file
-type ddirectory
-type lsymlink
-type pnamed pipe
-type ssocket
-type bblock device
-type ccharacter device
find /tmp -type f               # only files
find . -type d -name "__pycache__"
find /etc -type l               # all symlinks in /etc

Size filters#

find . -size +10M           # larger than 10 MB
find . -size -100k          # smaller than 100 KB
find . -size +1G -type f    # files over 1 GB
find . -empty               # zero-byte files or empty dirs

# Units: c (bytes)  k (KB)  M (MB)  G (GB)

Time filters#

find . -mtime -1          # modified within last 24 h
find . -mtime +30         # modified more than 30 days ago
find . -mtime 0           # modified today (0–24 h ago)
find . -newer /tmp/stamp  # modified after the stamp file
find . -atime -7          # accessed within 7 days
find . -ctime -1          # inode changed within 24 h

# -mmin / -amin / -cmin  for minutes instead of days
find . -mmin -60          # modified within last hour

Permission and ownership#

find . -perm 0644               # exactly 0644
find . -perm -0644              # at least these bits set
find . -perm /0111              # any execute bit set
find . -user alice              # owned by alice
find . -group wheel             # owned by wheel group
find . -not -user root          # not owned by root
find /tmp -perm -1777 -type d   # sticky-bit dirs (shared tmp)

Depth control#

find . -maxdepth 1              # only immediate children
find . -mindepth 2 -maxdepth 4  # depth 2–4 only
find . -maxdepth 0              # only the start path itself

Execute actions#

# {} is replaced by the current file path
find . -name "*.tmp" -exec rm {} \;          # delete one at a time
find . -name "*.sh" -exec chmod +x {} \;    # make executable
find . -type f -exec wc -l {} +             # batch with +  (faster)

# execdir β€” run command in the file's directory
find . -name "*.py" -execdir python -m py_compile {} \;

# Print with format
find . -name "*.log" -printf "%p\t%s\n"     # path + size (bytes)
find . -type f -printf "%T@ %p\n" | sort -n  # sort by mtime

Delete#

find . -name "*.pyc" -delete              # delete matching files
find . -type d -name __pycache__ -delete  # delete matching dirs
# -delete implies -depth; use with care

Prune (skip directories)#

# Skip .git and node_modules
find . -name ".git" -prune -o -name "node_modules" -prune -o \
       -name "*.js" -print

# General pattern: -path SKIP -prune -o EXPR -print
find . \( -path "./.git" -o -path "./dist" \) -prune \
       -o -type f -name "*.md" -print

Logical operators#

OperatorSyntax
AND (default)-a or nothing
OR-o
NOT! or -not
Grouping\( ... \)
find . \( -name "*.jpg" -o -name "*.png" \) -size +1M
find . -not \( -name "*.py" -o -name "*.sh" \)

Practical recipes#

# Top 10 largest files
find . -type f -printf "%s\t%p\n" | sort -rn | head -10

# Find files modified in the last 5 minutes (useful post-install)
find / -type f -newer /tmp/before -mmin -5 2>/dev/null

# Broken symlinks
find . -type l ! -exec test -e {} \; -print

# World-writable files (security audit)
find / -xdev -type f -perm -0002 2>/dev/null

# SUID/SGID binaries
find / -xdev \( -perm -4000 -o -perm -2000 \) -type f 2>/dev/null

# Find and compress logs older than 7 days
find /var/log -name "*.log" -mtime +7 -exec gzip {} \;

# Delete empty directories
find . -type d -empty -delete

# Replace string in all matched files (with sed)
find . -name "*.conf" -exec sed -i 's/oldhost/newhost/g' {} +

# Count files per extension
find . -type f | sed 's/.*\.//' | sort | uniq -c | sort -rn

# Find duplicate filenames (different paths)
find . -type f -printf "%f\n" | sort | uniq -d

Cross-filesystem#

find / -xdev -name "*.core"    # don't cross mount boundaries
find / -mount -name "lost+found"

[!TIP] Use find ... -exec cmd {} + (plus sign) instead of \; (semicolon) when possible. The + variant batches many filenames into a single cmd call, like xargs, and can be 10–100Γ— faster on large result sets.

[!WARN] -delete silently follows -depth order (deepest first). Test your expression with -print before replacing it with -delete.