Where to start First steps track · 15 stages
Linux Labs

find — searching for files

4 min GNU findutils

Finding files by name, size, time, permissions; acting on what's found.

Cheat sheet

9 commands Printable version
  • find /etc -name nginx.conf exact name, search from /etc
  • find ~ -type f -name site.conf files only, no directories
  • find . -name "*.log" by pattern (quote the pattern!)
  • find . -type f -size +100M large files
  • find . -mtime -1 modified in the last day
  • find . -name "*.tmp" -delete delete (test without -delete first!)
  • find . -type f -exec chmod 644 {} + mode 644 for every file found
  • find . -printf '%s %p\n' | sort -rn | head top by size
  • find . -path './node_modules' -prune -o -name '*.js' -print excluding a directory

Overview

find walks a directory tree and selects files by conditions (name, size, time, type, permissions), then can run an action on them.

bash
find <where> <conditions> <action>
find /var/log -name "*.log"       # by name

With no action, the default is -print (prints paths). Conditions combine: adjacent = AND; -o = OR; !/-not = NOT; grouping with \( ... \).

Options

10

Below are the main conditions and actions of find; the full list is in man find.

Option What it does Example
-name pattern Match by filename (a glob pattern, case-sensitive). find . -name "*.log"
-type f|d|l Match by type — a regular file, a directory, or a symlink. find . -type f
-size +N|-N Match by size (+ larger, - smaller; k/M/G units). find . -size +100M
-exec command {} + Run a command over the matches; {} + batches the arguments together. find . -type f -name "*.sh" -exec chmod +x {} +
-iname pattern Like -name, but case-insensitive. find . -iname "*.JPG"
-mtime +N|-N Match by modification time in days (-mmin for minutes). find . -mtime -1
-maxdepth N Limit the traversal depth; put it before other conditions. find . -maxdepth 2 -name "*.conf"
-xdev Don't cross filesystem boundaries (skip mounted filesystems). find / -xdev -name '*.iso'
-delete Delete every matched file; test without this flag first. dangerous find . -name "*.tmp" -delete
-prune Don't descend into a matched directory (combined with -path and -o to exclude it). find . -path './node_modules' -prune -o -name '*.js' -print

Nothing found. Try a shorter query.

Recipes

2

Conditions

bash
find . -name "*.conf"             # by name (case-sensitive)
find . -iname "*.JPG"             # case-insensitive
find . -regex '.*/.*\.(log|tmp)'  # by a regex on the full path
find . -type f                    # files only (d for directories, l for links)
find . -size +100M                # larger than 100 MB (-100k smaller than 100 KB)
find . -mtime -1                  # modified in the last day (-mmin -10 for 10 minutes)
find . -newer /tmp/marker         # newer than a marker file
find . -user alice -group devs    # owner/group
find . -perm -4000                # SUID files (security audit)
find . -empty                     # empty files/directories
find /home -xdev -name '*.iso'    # don't cross mount points
find . -path './node_modules' -prune -o -name '*.js' -print   # skip a directory

Actions

bash
find . -name "*.tmp" -delete                      # delete the matches
find . -name "*.log" -mtime +30 -delete           # logs older than 30 days
find . -type f -name "*.sh" -exec chmod +x {} +   # make them executable (+ = batched)
find . -type d -exec chmod 755 {} +               # permissions on directories
find . -name "*.conf" -exec grep -l TODO {} +     # grep across the matches
find . -name "*.bak" -ok rm {} \;                 # -ok = ask for confirmation
find . -name "*.bak" -print0 | xargs -0 rm        # via xargs (names with spaces)
find . -type f -printf '%s %p\n' | sort -rn | head # the largest files (-printf)

{} + batches arguments (faster), {} \; runs one at a time. -print0/xargs -0 are safe for names with spaces (see xargs).

Troubleshooting

5

"Permission denied" clutters the output

Drop the errors: find / -name foo 2>/dev/null.

It searches too deep / across other filesystems

-maxdepth N limits the depth (put it BEFORE other conditions); -xdev avoids crossing mount points (see mount).

Accidentally deleted the wrong thing with -delete

Always run it without an action first (just the listing), confirm the list, then add -delete/-exec rm. -delete implies -depth — the order of conditions matters.

find with -name finds nothing

The pattern must be quoted ("*.log"), otherwise the shell expands it before find sees it. For case-insensitivity, use -iname.

-exec is slow

{} \; runs the command once per file. Switch to {} + (batched) or xargs.

See also

  • grep — Searching for patterns in text; regex, recursion, context.
  • disk-usage — Where the space and inodes went — df, du, finding large files, pitfalls.
  • chmod-chown — Changing permissions (chmod) and owner/group (chown) — numeric and symbolic syntax.
Loading…