Files
my-docs/Linux/Basic-Administration/29-find.md

10 KiB
Raw Blame History

find — quick reference & practical documentation

This is a compact, practical reference for the Unix/Linux find command aimed at DevOps engineers and system administrators. It covers common options, tests, actions, operators, examples (safe and practical) and performance tips.


Synopsis

find [path...] [expression]

If no path is given, find searches the current directory (.). expression is evaluated left-to-right and can contain tests, actions and operators.


Basic behaviour

  • find walks directory trees recursively by default.
  • An expression evaluates to true/false; when true, the default action -print (or whatever action is specified) is executed.
  • You can control traversal order with -depth and -maxdepth/-mindepth.
  • -prune prevents descending into directories.

Common options and switches

  • -H : follow symbolic links specified on the command line.
  • -L : follow all symbolic links.
  • -P : never follow symbolic links (default).
  • -xdev : don't descend into directories on other filesystems (useful when walking /).
  • -mindepth N : do not apply tests/actions to files at depth < N.
  • -maxdepth N : do not descend past depth N.
  • -depth : process directory contents before the directory itself (useful for safe deletes).
  • -mount : same as -xdev (GNU find).

Common tests (predicates)

  • -name pattern : match basename with shell globbing (case-sensitive). Pattern uses shell wildcards (*, ?, []).

  • -iname pattern : case-insensitive -name.

  • -path pattern : match the whole path (slash-separated) with shell globbing.

  • -ipath pattern : case-insensitive -path.

  • -regex pattern : match full path with regular expression (syntax differs by find implementation; GNU find defaults to Emacs regex).

  • -type c : file type; f = regular file, d = directory, l = symlink, c = character device, b = block device, p = FIFO, s = socket.

  • -perm mode : file permission test. Modes:

    • octal: -perm 0644 (exact)
    • symbolic: -perm -u=w (any of the bits), -perm /u=w (any), -perm -0644 (all bits set)
    • GNU find also accepts /mode to mean "any of the bits".
  • -user name / -uid uid : owner.

  • -group name / -gid gid : group.

  • -size n[cwbk] : file size; default 512-byte blocks for some find versions; most use 1K blocks for k. GNU find suffixes:

    • c = bytes
    • k = kilobytes
    • M = megabytes
    • G = gigabytes
    • +n = greater than n, -n = less than n, n = exactly n
  • -mtime n / -atime n / -ctime n : modified / accessed / changed time in 24-hour periods; -mtime +7 older than 7 days, -mtime -7 less than 7 days, -mtime 7 exactly 7.

  • -mmin n, -amin n, -cmin n : minutes.

  • -newer file : newer than file (can be combined with ! to negate).

  • -empty : empty file or directory.

  • -links n : number of hard links.

  • -readable / -writable / -executable : access checks from running user perspective.


Common actions

  • -print : print path (often default; some implementations require explicit -print with complex expressions).
  • -print0 : print paths separated by NUL (safe with whitespace/newlines).
  • -ls : list file using ls -dils style.
  • -exec command {} \; : run command once per matched file. {} is replaced by the current path. The \; terminator must be escaped or quoted.
  • -exec command {} + : optimized form; appends multiple matches to command arguments like xargs (more efficient).
  • -ok command {} \; : like -exec but prompts the user before each execution.
  • -delete : delete matched files/directories (be careful; obeys ordering and -depth).
  • -prune : exclude directory from descent (returns true; often used with -o).
  • -quit : stop after first match (very efficient when used with -print).
  • -mindepth N, -maxdepth N already described; they behave like tests.

Operator precedence (GNU find style)

  • Parentheses ( ) group expressions. They must be escaped or quoted: \( ... \) or '(' ... ')'.

  • ! or -not : logical NOT (unary).

  • -a or implicit concatenation : logical AND.

  • -o or -or : logical OR.

  • Evaluation is left-to-right; -a has higher precedence than -o. Use parentheses to be explicit.

  • Common pitfall: mixing -prune and -o requires careful grouping: Example pattern to exclude dir:

    find . -path ./dir -prune -o -print
    

    This means: if path is ./dir prune it (and -prune returns true) otherwise (-o) -print.


Typical practical examples

Search examples assume bash shell; escape parentheses and semicolons as needed.

  1. Find files by name (case-sensitive)
find /var/log -type f -name "syslog*"
  1. Case-insensitive:
find /home -type f -iname "*.jpg"
  1. Find empty directories:
find /path -type d -empty
  1. Delete *.tmp files safely (print first, then delete)
find /data -type f -name "*.tmp" -print
find /data -type f -name "*.tmp" -delete

Or safer with confirmation:

find /data -type f -name "*.tmp" -ok rm {} \;
  1. Find and remove files older than 30 days (safe: use -print first)
find /var/log -type f -mtime +30 -print
find /var/log -type f -mtime +30 -exec rm -- {} +

Prefer -exec ... + over -exec ... \; for efficiency.

  1. Remove directories older than 30 days (use -depth to ensure files inside are removed first)
find /tmp -depth -type d -mtime +30 -exec rm -rf -- {} +

-delete may also be used but beware of ordering; -depth ensures children processed before parent.

  1. Find files with spaces and handle them safely:
find /srv -type f -name "*.conf" -print0 | xargs -0 grep -H "pattern"
  1. Find files larger than 100 MiB:
find / -type f -size +100M -print
  1. Find files newer than a reference file:
find /web -type f -newer /tmp/deploy_marker -print
  1. Find and run a command on many files (batching):
find /data -type f -name "*.log" -exec gzip -- {} +
  1. Exclude a directory (dir_to_skip) while listing everything else:
find . -path "./dir_to_skip" -prune -o -print
  1. Only search one level (non-recursive):
find . -maxdepth 1 -type f -print
  1. Find broken symlinks:
find / -xtype l -print

Note: -xtype tests the target type; -L changes behavior of -type.

  1. Use -printf to customize output (GNU find):
find . -type f -printf "%p\t%k KB\t%TY-%Tm-%Td %TH:%TM:%TS\n"

-printf supports format sequences (%p path, %s bytes, %k KB blocks, %TY year, ...). Exact spec depends on implementation (GNU has extensive options).

  1. Stop at first match (fast):
find /usr -type f -name "passwd" -print -quit
  1. Find files modified within last 15 minutes:
find /var -type f -mmin -15

Safe deletion checklist

  • Always -print or -ls first to verify matches.
  • Prefer -exec rm -- {} + or use -delete with -depth if required.
  • Watch out for -maxdepth/-mindepth to avoid accidental top-level deletions.
  • Use -print0 + xargs -0 when passing to other utilities.
  • Consider using -ok for destructive changes in interactive contexts.

Performance & scalability tips

  • Limit scope: pass explicit starting paths instead of . or / when possible.
  • Use -maxdepth and -mindepth to reduce traversal.
  • Use -xdev to avoid crossing filesystem boundaries (speeds up root scans).
  • Combine fast tests early (e.g., -type f -name "*.log" rather than -name alone) because find evaluates left-to-right; short-circuiting happens when possible.
  • Prefer -exec ... + to -exec ... \; to reduce process spawn overhead.
  • Use -prune to skip large tree branches that arent needed.
  • On very large trees consider tools optimized for indexing (e.g., locate / mlocate, fd, or ripgrep for content search). find is always consistent but traverses the disk each run.

Portability notes

  • Behavior, available tests/actions and argument formats vary slightly between implementations (GNU find vs BSD find vs BusyBox). Examples above assume GNU find when using -printf, -delete, -quit or suffixes like M/G for sizes.
  • When writing scripts for mixed environments, try to stick to portable tests: -name, -type, -mtime, -print, -exec ... \;. Check /usr/bin/find --version or man find on target hosts.

Gotchas & common pitfalls

  • Shell globbing vs find globbing: -name "*.txt" is matched by find and must be quoted to prevent shell expansion.
  • -perm exact vs any-bit semantics differ across versions; test on target system.
  • -regex matches the whole path, not just basename; regex dialect differs (use -regextype posix-extended on GNU find to set type).
  • -delete will fail if used before tests that select children (order matters). Use -depth or test ordering appropriately.
  • Beware of running find as root with -exec rm -rf {} — very dangerous if expression is wrong. Always verify output.
  • -maxdepth/-mindepth may not be supported in very old find implementations.

Exit status

  • 0 : at least one match and command completed successfully.
  • 1 : no matches were found (behavior can vary).
  • >1 : an error occurred (e.g., permission errors or malformed expression). Note: exact meanings can depend on implementation.

Useful combinations

  • Find files and preserve relative paths for tar:
cd /path && find . -type f -name "*.conf" -print0 | tar --null -T - -czf confs.tar.gz
  • Find and change ownership or permissions:
find /srv/www -type f -name "*.php" -exec chown www-data:www-data {} +
find /srv/www -type d -exec chmod 755 {} +
  • Search content in matched files:
find /app -type f -name "*.py" -print0 | xargs -0 grep -n "TODO"

Related commands/tools

  • locate / mlocate : fast filename lookup (uses database).
  • fd : simpler, faster user-friendly alternative to find (not always installed).
  • xargs : pass batches of arguments to commands (careful with spaces; use -print0 + xargs -0).
  • stat : detailed file metadata for a single file.
  • rm, tar, gzip, chown, chmod, rsync : commonly used alongside find.

Quick cheatsheet (most-used patterns)

  • Find files by name: find /path -type f -name "pattern"
  • Case-insensitive: -iname
  • Size bigger than 100M: -size +100M
  • Modified > 7 days: -mtime +7
  • Delete old files: find /dir -type f -mtime +30 -exec rm -- {} +
  • Print NUL-separated: -print0
  • Safe prune: find . -path ./skip -prune -o -print
  • Batch exec: -exec cmd {} +
  • Stop on first: -print -quit