find walks a directory tree and prints every file that matches your conditions. It can search by name, size, age, owner and permissions, and run a command on each result. Here are the patterns you’ll actually use on a server.

The basic form:

find [where] [conditions] [action]

If you omit the action, find prints the paths.

Search by name

find /var/www -name "wp-config.php"        # exact name, case-sensitive
find /home -iname "*.jpg"                   # case-insensitive pattern
find . -name "*.log" -o -name "*.tmp"       # either pattern
find /etc -name "*.conf" -not -name "*.dpkg*"

Always quote patterns. Unquoted, the shell expands *.log in the current directory before find sees it.

Match on the full path instead of the file name:

find /var/www -path "*/cache/*" -name "*.php"

Search by type

find /srv -type f        # regular files
find /srv -type d        # directories
find /srv -type l        # symbolic links
find /srv -xtype l       # broken symlinks

Search by size

find / -type f -size +500M 2>/dev/null     # larger than 500 MB
find /var/log -type f -size +100M
find . -type f -size -1k                    # smaller than 1 KB
find . -type f -empty                       # empty files
find . -type d -empty                       # empty directories

Units: c bytes, k KiB, M MiB, G GiB. 2>/dev/null hides “Permission denied” noise. For a disk-full emergency, see finding large files on Linux.

Search by time

find /var/www -type f -mtime -1        # modified within the last 24 hours
find /var/www -type f -mmin -30        # modified within the last 30 minutes
find /backups -type f -mtime +30       # modified more than 30 days ago
find /tmp -type f -atime +7            # not accessed for 7+ days
find . -newer reference.txt            # modified after reference.txt
find . -newermt "2026-10-01"           # modified after a date

-mtime counts in whole days, rounding down: -mtime +30 means “more than 30 full days”. Recently modified PHP files in a web root are a classic sign of compromise:

find /var/www -name "*.php" -mtime -2 -ls

Search by owner and permissions

find /var/www -user root                   # owned by root
find /var/www ! -user www-data             # not owned by www-data
find /home -nouser                          # owner no longer exists
find / -perm -4000 -type f 2>/dev/null     # setuid binaries (security audit)
find /var/www -type f -perm 0777           # world-writable files
find /var/www -type f -perm /o+w           # anything writable by "others"

-perm 0644 means exactly 0644; -perm -0644 means at least those bits; -perm /0022 means any of those bits.

Limit depth and skip directories

find . -maxdepth 1 -type f                 # current directory only
find /var -mindepth 2 -maxdepth 3 -name "*.log"
find . -path ./node_modules -prune -o -name "*.js" -print
find / -xdev -size +1G                     # don't cross into other filesystems

-prune is how you exclude a directory efficiently: find doesn’t descend into it at all. -xdev keeps a search of / from wandering into /proc or mounted network shares.

Run a command on each result

find . -name "*.sh" -exec chmod +x {} \;       # one command per file
find . -name "*.log" -exec gzip {} +           # batch many files per command (faster)
find . -type f -name "*.php" -exec grep -l "eval(base64_decode" {} +
find . -name "*.bak" -ok rm {} \;              # ask before each

{} is replaced by the path. Ending with \; runs the command once per file; + passes as many files as fit into one command line, which is much faster for thousands of files.

Fix permissions in a web root

The classic pair:

find /var/www/example.com -type d -exec chmod 755 {} +
find /var/www/example.com -type f -exec chmod 644 {} +

Delete files safely

find /var/backups -name "*.sql.gz" -mtime +14 -print     # 1. look first
find /var/backups -name "*.sql.gz" -mtime +14 -delete    # 2. then delete

Put -delete last. find evaluates left to right, so find . -delete -name "*.tmp" deletes everything before it ever checks the name.

Pipe into xargs

When file names may contain spaces, use null separators:

find . -name "*.jpg" -print0 | xargs -0 -P 4 -n 20 jpegoptim --strip-all

-P 4 runs four processes in parallel. See the xargs command for more.

Format the output

find . -type f -printf "%s\t%p\n" | sort -n | tail     # size and path, largest last
find . -type f -printf "%TY-%Tm-%Td %p\n"               # modification date and path
find /var/log -type f -ls                                # ls -l style listing

Count things

find /var/www -type f | wc -l            # number of files
find . -type f -name "*.php" | wc -l

Running out of inodes rather than space? Count files per directory to find the culprit — see inode usage full.

find vs locate

locate searches a prebuilt index and is instant, but the index is only as fresh as the last updatedb run. find always reflects the current state of the disk. On servers, find is the dependable choice.

Quick reference

Goal Command
By name find /path -name "*.conf"
Files only -type f
Bigger than 1 GB -size +1G
Changed in last day -mtime -1
Older than 30 days -mtime +30
Owned by user -user www-data
One level deep -maxdepth 1
Exclude a dir -path ./skip -prune -o … -print
Run command -exec cmd {} +
Delete … -delete (last!)

find pairs naturally with grep — find the files, grep inside them. Practise these commands on any Linux VPS; a scratch server is the safest place to try -delete.

  • Linux
  • Command Line
  • find