How-to

The find Command in Linux: Searching Files by Name, Size and Date

Updated: · Skillaria.Top

The find command walks a directory tree and selects files by conditions: find /path -name '*.log' searches by name, -type f only regular files, -size +100M larger than 100 MB, -mtime -7 changed within a week. Conditions can be combined, and an action can be run on the results with -exec, -delete, or the list can be passed to xargs.

The find command walks a directory tree and locates files by conditions: name, type, size, modification date, owner and permissions. The general pattern is find [where to search] [conditions] [action]. Below are find linux examples for typical tasks: finding a config file, cleaning up old logs, and tracking down what is filling the disk.

The find command syntax

find /var/log -type f -name '*.log' -mtime +30 -print

Let us break it down:

  • /var/log — the starting point. You can give several directories in a row or . (the current one). Without a path, GNU find searches the current directory.
  • -type f -name '*.log' -mtime +30 — conditions (the documentation calls them tests). By default they are joined with a logical AND.
  • -print — the action: print the path. It is added automatically when no other action is given.

find works recursively, going into all nested directories. If you run it as a regular user over system paths, the output will be cluttered with Permission denied lines. Remove them by redirecting the error stream:

find / -name 'nginx.conf' 2>/dev/null

Searching by name: -name and -iname

The -name condition compares only the file name (without the path) with a pattern. The pattern supports * (any characters), ? (one character) and [abc] (one of the listed characters).

# exact name
find /etc -name 'hosts'

# all .conf files
find /etc -name '*.conf'

# case-insensitive: README.md, readme.MD, Readme.md
find ~/projects -iname 'readme.md'

# report_1.csv ... report_9.csv
find . -name 'report_?.csv'

Always put the pattern in quotes. Without them the shell expands *.conf against the files in the current directory, so find receives a list of names instead of a pattern — the result will be unexpected, or the command fails with the error paths must precede expression.

Searching by path: -path and -regex

If the directory matters, not just the name, use -path — it compares the pattern against the whole path:

# .js files only inside src directories
find . -path '*/src/*' -name '*.js'

For complex patterns there is -regex (a regular expression also matched against the full path) and -iregex for case-insensitive matching:

find . -regextype posix-extended -regex '.*\.(jpg|jpeg|png)$'

How to exclude a directory

To stop find from entering, for example, node_modules or .git, use -prune:

find . -path ./node_modules -prune -o -name '*.js' -print

Read it like this: "if the path is ./node_modules, do not descend into it, otherwise (-o) print the *.js files". An explicit -print at the end is required, otherwise the excluded directory itself would be printed too. A simpler but slower option is -not -path '*/node_modules/*': find still walks the directory, it just filters the results.

Searching by type: -type

ValueWhat it finds
-type fregular files
-type ddirectories
-type lsymbolic links
-type ssockets
-type pnamed pipes (FIFO)
# only directories named logs
find / -type d -name 'logs' 2>/dev/null

# empty files and empty directories
find . -type f -empty
find . -type d -empty

# broken symbolic links
find . -xtype l

Searching by size: -size

The -size condition takes a number with a suffix: c — bytes, k — kilobytes, M — megabytes, G — gigabytes. The + sign means "greater than", - means "less than", and no sign means "exactly".

# files larger than 100 MB across the whole system
find / -type f -size +100M 2>/dev/null

# from 10 to 50 MB
find . -type f -size +10M -size -50M

# less than 1 KB
find . -type f -size -1k

There is a catch: the size is rounded up to the unit. That is why -size -1M finds only empty files — after rounding, any non-empty file takes "at least 1 megabyte". For exact limits use smaller units: -size -1024k.

What is taking up disk space

Combining find with ls and sort shows the largest files:

find /var -type f -size +50M -exec ls -lh {} + 2>/dev/null | sort -k5 -rh | head
-rw-r----- 1 syslog adm  1.2G Oct 14 09:12 /var/log/syslog.1
-rw-r--r-- 1 root   root 412M Oct 10 03:00 /var/backups/db.sql.gz
-rw-r----- 1 root   adm   96M Oct 14 09:15 /var/log/nginx/access.log

To estimate whole directories, du -sh is more convenient, while find is useful when one huge file somewhere deep inside is the culprit.

Searching by date: -mtime, -mmin, -newer

Every file has three timestamps, and find can filter by each of them:

ConditionTimestampUnit
-mtime / -mmincontent modificationdays / minutes
-atime / -aminlast readdays / minutes
-ctime / -cminmetadata change (permissions, owner, name)days / minutes

The signs work the same way as for size: -mtime -7 means modified less than 7 days ago, -mtime +30 means more than 30 days ago.

# changed in the last week
find ~/projects -type f -mtime -7

# logs older than 30 days
find /var/log -type f -name '*.log' -mtime +30

# changed in the last 15 minutes
find /etc -type f -mmin -15

Days are counted as whole 24-hour periods, and the fractional part is dropped. Because of this, -mtime +1 finds files older than 48 hours, not 24 — a common trap. If you need precision, switch to minutes: -mmin +1440.

Files newer than another file or a date

# changed after deploy.lock was last modified
find . -type f -newer deploy.lock

# changed after a specific date (GNU find)
find . -type f -newermt '2026-10-01'

# within a date range
find . -type f -newermt '2026-10-01' ! -newermt '2026-10-08'

Searching by owner and permissions

# files owned by alice
find /home -user alice

# files without an existing owner (after a user was deleted)
find / -nouser 2>/dev/null

# files with exactly 777 permissions
find /var/www -type f -perm 777

# files writable by everyone
find /var/www -perm -o=w

# files with the SUID bit — useful for security audits
find / -perm -4000 -type f 2>/dev/null

The -perm condition has three forms: without a sign, the permissions must match exactly; with -, at least all the listed bits must be set; with /, at least one of them must be set.

Logic of conditions: AND, OR, NOT

Conditions are joined with AND by default. For OR use -o, for negation use ! or -not. Grouping is done with parentheses, which must be escaped from the shell:

# jpg or png pictures
find . -type f \( -name '*.jpg' -o -name '*.png' \)

# everything except .tmp files
find . -type f ! -name '*.tmp'

Without parentheses, -type f would apply only to the first condition of the OR pair, and directories named *.png would end up in the results. The spaces around \( and \) are required.

Search depth: -maxdepth and -mindepth

# only in the current directory, no nested ones
find . -maxdepth 1 -type f -name '*.sh'

# starting from the second level of nesting
find . -mindepth 2 -name '*.md'

# do not cross into other filesystems
find / -xdev -type f -size +1G

Put -maxdepth right after the path, before the other conditions — otherwise GNU find prints a warning. The -xdev option is useful when searching from /: find will not go into /proc, network or mounted disks.

Actions on results: -exec, -delete, xargs

-exec: run a command for each file

Instead of {} find substitutes the file path. The command ends with \; or +:

# one run per file
find . -name '*.sh' -exec chmod +x {} \;

# all files in one list — faster
find . -name '*.log' -exec gzip {} +

# with confirmation for each file
find . -name '*.bak' -ok rm {} \;

The + variant gathers paths into batches and runs the command much less often, so on thousands of files it is several times faster. The \; variant is needed when the command accepts only one file or when {} is not at the end.

-delete: remove what was found

# first look at what would be deleted
find /tmp/build -type f -name '*.o' -mtime +7

# then delete
find /tmp/build -type f -name '*.o' -mtime +7 -delete

Always run the command without -delete first and check the list. Also put -delete last: find evaluates the expression from left to right, and find . -delete -name '*.o' will delete everything in the directory before checking the name.

find and xargs

A classic combination is passing the list of files to another program through xargs. To avoid breaking on names with spaces, use the null byte as a separator:

find . -type f -name '*.txt' -print0 | xargs -0 wc -l

The -P flag of xargs runs the processing in parallel:

find ./images -name '*.png' -print0 | xargs -0 -P 4 -n 10 optipng

find and grep: searching text inside files

find searches for files, not their contents. To find a string inside the selected files, pass them to grep:

# where listen 8080 appears in the configs
find /etc/nginx -type f -name '*.conf' -exec grep -Hn 'listen 8080' {} +
/etc/nginx/sites-enabled/app.conf:4:    listen 8080;

The -H flag prints the file name, -n the line number, and grep -l prints only the names of files with a match. If you only need to filter by extension, grep alone is enough: grep -rn --include='*.conf' 'listen 8080' /etc/nginx.

Custom output format: -printf

GNU find can print more than just the path. For example, the size, the date and the name:

find . -maxdepth 1 -type f -printf '%s\t%TY-%Tm-%Td\t%p\n' | sort -n

Here %s is the size in bytes, %T... is the modification date broken into parts, and %p is the path. This is convenient in scripts: there is no need to parse the output of ls.

Cheat sheet: everyday find linux examples

TaskCommand
Find a file by namefind / -name 'file.txt' 2>/dev/null
Ignore casefind . -iname '*.jpg'
Directories onlyfind . -type d -name 'cache'
Files larger than 1 GBfind / -xdev -type f -size +1G
Changed within a dayfind . -type f -mtime -1
Changed within an hourfind . -type f -mmin -60
Delete logs older than 30 daysfind /var/log/app -name '*.log' -mtime +30 -delete
Empty directoriesfind . -type d -empty
Change permissions of all directoriesfind . -type d -exec chmod 755 {} +
Text inside filesfind . -name '*.py' -exec grep -l 'TODO' {} +
Count filesfind . -type f | wc -l

Common mistakes

  • A pattern without quotes. find . -name *.log breaks if the current directory contains even one .log file. Write '*.log'.
  • A flood of Permission denied. Add 2>/dev/null or run with sudo if you really need the whole disk.
  • -delete in the wrong place. It always goes last, and a dry run without deletion should come before it.
  • Names with spaces in a pipeline. find ... | xargs rm will split "My File.txt" into two arguments. Use -print0 with xargs -0, or -exec.
  • Expecting exact days from -mtime. For exact intervals use -mmin or -newermt.

Summary

find is a universal tool for searching the file system: a path, then conditions on name, type, size, date and permissions, then an action. Master the five pillars — -name, -type, -size, -mtime and -exec ... + — and most tasks take a single line. Repeat the find linux examples above in your own terminal, and we work through combining find with grep, sed and awk in practice in the Linux course lecture on text processing in the terminal.

FAQ

How is find different from locate?

locate searches a prebuilt database of names, so it is instant, but it does not see files created after the database was last updated by the updatedb command. find walks the disk in real time and can filter by size, date and permissions.

How do I find a file by its content rather than its name?

find itself does not read contents. Use grep -rn 'text' /path, or the combination find . -name '*.conf' -exec grep -l 'text' {} +.

Why is find slow when run on the root of the disk?

It walks all directories, including /proc, /sys and mounted disks. Limit the search to a specific directory, add -xdev and -maxdepth, or exclude unneeded paths with -prune.

Can find results be sorted by date?

Yes: find . -type f -printf '%T@ %p\n' | sort -n lists files from oldest to newest, where %T@ is the modification time in seconds since the epoch.

How do I find and delete empty directories?

The command find . -type d -empty -delete removes all empty directories, including those that became empty after nested ones were deleted. Run it without -delete first and check the list.

Learn this topic on video

This topic is covered in depth with practice in the course “Linux: с нуля до уверенного администрирования”.

Go to course