Search notes:

Shell command: find

find [-H] [-L] [-P] [-D debugopts] [-Olevel] [dir…] [expression]
find descends into a filesystem hierarchy below dir (when omitted the current directory) and evaluates expression (if none given then -print) for each file or directory it encounters.

Expressions

An expression is one of:
criteria (test) identifies matched files
action performed with the name of the mached file
The behavior of the evaluation of the tests and actions can be influenced with options.
find distinguishes between
Criteria, actions and options evaluate to a boolean value (true or false).
The value of any option is true.
Operators logically combine the (boolean) values of the criteria, actions and options and evaluate to a resulting boolean value.

Operators

Operators in decreasing order of precedence are:
( expr ) Force precedence. Because paranthesis usually have a meaning in a shell, they need to be escaped: \( expr \)
! expr or -not expr Negation of expr (-not is not POSIX compliant)
expr1 expr2 Shorthand for expr1 -a expr2
expr1 -a expr2 or -and expr2 AND-evaluation. Lazyly evaluated. -and is not POSIX compliant
expr1 -o expr2 or expr1 -or expr2 OR-evaluation. Lazyly evaluated. -or is not POSIX compliant
expr1, expr2[, …] List: all expressions are evaluated. The list evaluates to the value of the last expression.
The default operator is -a (and). So, the following two commands are equivalent:
$ find . -name xyz    -print
$ find . -name xyz -a -print

Understanding the working of find

Unix Power Tools has the following quote about find:
find's business is evaluating expressions - not locating files. Yes, find certainly locates files; but that's really just a side effect. For me, understanding this point was the conceptual breakthrough that made find much more useful.
My first aha experience was to discover that tests and actions are by default combined with -a (logical and) if the operator is missing.
Thus the following two commands are equivalent:
# Implicit and:
find . -path '*xyz*'    -print

# Explicit and:
find . -path '*xyz*' -a -print

Lazy evaluation

The second aha experience was to find out that find evaluates its arguments lazily.
In the following example, each file or directory name is compared with ./bin/debug.
If the name differs, -path ./bin/debug returns false and there is no point in also evaluating -prune (which is implicitly connected to -path with -and). Because -path … -and -prune is false, find needs to also evaluate -print to check if the entire expression is true.
However, if the name matches, find also evaluates -prune to check if -path ./bin/debug -and -prune is true. If the path is a directory, -prune evaluates to true and find does not descend into this directory. The name of the directory in that case is not printed because -path … -prune is true and there is no point in also evaluating -print.
$ find . -path ./bin/debug -prune -o -print

Tests (criteria)

The test operators check various file properties and return either true or false.
Some tests take a numerical value (marked as n in the table below). In this case, the value of n can be +n (value is greater than n), -n (value is less than n) or simply n (value must be exactly n).
Some of these tests come in a case-sensitive and case-insensitive variant (-i…).
Variants of the tests that text case insensitiveli are listed in the 3rd column.
-amin n File's last access time, in minutes
-anewer reference File's last access time, in n*24 hours
-atime n
-cmin n
-cnewer reference
-ctime n
-empty File (or directory?) is empty
-executable Checks if file (or directory) is executable by current user, taking into account access control lists (which -perm ignores). Compare -readable
-false Always false.
-fstype type
-gid n
-group gname Files that belong to a given group, compare with -user
-inum n Inode number
-links n Number of hard links
-lname pattern Symbolic link whose content matches the shell pattern pattern -ilname
-mmin n
-mtime n
-name pattern Searches in files' and directories' basename. In order to search accross the directory separator (/), see -wholename and -path -iname
-newer reference
-newerXY reference
-nogroup
-nouser
-path pattern -ipath
-perm [-|+|/mode] Permission bits: (mode: exactly, -mode: all bits, /mode: any bit, +mode: deprecated). Compare -executable
-readable Checks if file (or directory) is executable by current user, taking into account access control lists (which -perm ignores). Compare -executable
-regex pattern Checks if regular expression matches whole path of file (see also here). Specify regex dialect with the -regextype option -iregex
-samefile name
-size n[cwbkMG] File size. c = bytes, b = blocks (512 bytes, the default), w: two-byte words, k: kibi-bytes (1024), M: Mebi-bytes (1024²), G: 1024³
-true
-type x x is one of b (block device), c (character device), d (directory), p (named pipe), f (regular file), l (symbolic link), s (socket), D (door, Solaris only?). (Compare with the shell command test)
-uid n
-used n
-user uname Files that belong to a given user, compare with -group
-wholename pattern Less portable than -path. See also -name -iwholename
-writable
-xtype c
-context pattern SELinux only

Positional options

The so-called position options influence the interpretation of the test operators:
-daystart Causes -amin, -atime, -cmin, -ctime, -mmin and -mtime to measure time from the beginning of today rather than 24 hours ago.
-follow Deprecated in favor of -L
-regextype Sets the regular expression dialect used for -regex and -iregex. Valid regex types seem to be: findutils-default, ed, emacs, gnu-awk, grep, posix-awk, awk, posix-basic, posix-egrep, egrep, posix-extended, posix-minimal-basic, sed
-warn, -nowarn Turn on or off warnings.

Actions

-delete Deletes the file or empty directory and returns true if successful. Using -delete automatically turns on the -depth option.
-exec cmd ; Replaces {} in cmd with the current file name then executes the cmd with the working directory begin the starting directory. Returns true if cmd exits with 0?
-exec cmd {} + Similar to above, but performs an xargs like assembling of the command. Always returns true.
-execdir cmd, -execdir command {} + Like -exec but command is executed with the working directory set to the directory where the file resides.
-fls file Like -ls but write to file like -fprint.
-fprint file Writes full filename to file and returns true.
-fprint0 file Like -print0 but write to file like -fprint.
-fprintf file format
-ls ls -dils on current file, return true
-ok cmd ; Like -exec but ask user before executing command.
-okdir cmd ; Like -execdir but ask user before executing command.
-print Print full incl. new line name on stdout, return true.
-print0 Print full name followed by NUL character on stdout. (Compare to -0 option of xargs)
-printf format true
-prune If file is a directory, do not descend into it and return true. If -depth is also specified, -prune has no effect. (Note that -depth is implied by -delete).
-quit Immediately exit the find process. Useful to check for the existence of a given file: find $dir -name xyz -print -quit

Search in path names

The -path option concatenates the path and filename to match files.
The following command finds files like ./abc/def/ghi/jkl:
find . -path '*bc*f*g*l' 

-inum

Finds the file with an inode (that can be found for example with ls -i.
This option is useful to remove files with special characters.

Find files case insensitively

Use the -iname argument:
$ find . -iname '*foo*'

Find files that were changed during a certain period

During the last 5 minutes

$ find . -cmin -5
Note the minus in front of the five: this finds files changed between 0 and 5 minutes. with -cmin 5 only files changed exactly five minutes ago would be found. -cmin +5 find files changed earlier than five minuts ago.
GNU understands date reference strings that can be given to date -d.
$ find . -newermt '5 minutes ago'

During the last n days

Similarly, files that were changed during the last week can be found so
$ find . -ctime -7

Files that are not owned by someone

With the exclamation mark, a premisse can be negated. This allows to search for files thare not owned by some specific user:
$ find . ! -user rene -print

Excluding directories

Directries can be excluded with -path ./path/do/excluded/dir -prune.
Note -prune (as -print) always returns true.
Therefore, it will probably be followed by -o.
I most cases, imho, -prune should be combined with -path (not with -name).
Find all files that contain a b in the filename but are not located under ./git:
$ find -path ./git -prune -o -type f -name '*b*' -print
Excluding multiple directories:
$ find / -path /foo/bar/baz  -prune  -o \
         -path /abc/def      -prune  -o \
         -path /usr/include  -prune  -o \
         -print

Finding files with special permissions

The -perm option allows to find files with specific permissions (such as readable by me, writeable by group or executable by anyone).

Creating some test files

In order to test this -perm option, we create some test files. The following script creates each possible file mode, that is in total 84 (= 4096).
# vi: ft=sh

[[ -d files ]] && rm -rf files

mkdir files

#   Iterate over each possible mode
for file_mode_octal in {0..7}{0..7}{0..7}{0..7}; do

  # Create a file …
    touch x
  # … and change its mode
    chmod $file_mode_octal x

  # Use ls's long listing format to determine the
  # humanly readable flags.
    flags_human_readable=$(ls -l x | cut -d' ' -f 1)

  # We have to remove the first character from flags_human_readable,
  # because signifies if the object is a file, directory, socket etc.
  # This # information is uninteresting for now:
    flags_human_readable=${flags_human_readable:1}

  # We move the file and name it with both the octal and the humanly
  # readable representation of the file:
    mv x files/${file_mode_octal}___${flags_human_readable}

done
Github repository shell-commands, path: /find/perm/create-files

Find a file with exact mode

When find's -perm option is given a octal number, it finds all files that have exactly these bits set.
find files -perm 1234
It's also possible to find for an exact permission with a symbolic notation. The following example finds all files that are -----x--:
find files -perm g=x
In order to specifiy multiple bits with the symbolic notation, they must be concatenated with a comma.
The following example finds als files that are r----x---.
find files -perm u=r,g=x

Find files with all desired bits set

The following example finds files that are executable by the user and readable the group and readable by others.
find files -perm -u=x,g=r,o=r

Find files with any desired bits set

The following example finds files that are executable by the user or readable the group or readable by others.
find files -perm /u=x,g=r,o=r

Find files owned by a given group and setgid set

The following command finds files that are owned by the group tty and have the setgid bit set:
$ find /usr/bin -type f -group tty -perm -g=s

Regular expression

The -regex pattern evaluates to true if the regular expression pattern matches the entire path, i. e. as though pattern was enclosed in ^…$.
The following command finds all files that have ancestor directory (immediate or not) named release-notes and the text 1.7 in their file name:
find -type f -regex '.*/relase-notes/.*1\.7.*'

Files that are not world readable

find files -not -perm /o=r

-regextype

-regextype allows to choose the regular expression syntax format.
I believe the format that comes closes to Perl Compatible Regex Expressions (PCRE) is either gnu-awk or posix-awk.
Find files that contain either 32 or 64 in their name:
$ find -regextype posix-awk -regex '.*(32|64).*'

Recursively find files containing a regular pattern

The following command recursively finds files that contain a regular expressions.
In order to prevent Permission denied error messages, the command prunes unreadable directories and then limits the grep command to files that are readable.
Because files in the .git directory usually not interesting, the command also prunes it:
$ find .                                                      \
       -path ./.git        -prune                          -o \
       -type d ! -readable -prune                          -o \
       -type f   -readable -exec grep -i 'find me if.*can' {} \;
Unfortunately, the Permission denied error message might still occur for directories that are not readable.

Find executables

-execute finds executable files and directories. In order to just find executables (such as binaries or shell scripts), the search must be further restricted to files (-type f):
find -executable -type f
The previous command also finds shared objects (which typically end in .so or .so.6.1). If these should not be included in the result, they can be excluded with a regular expression:
find -executable -type f -not -regex '.*\.so\(\.\d\)?.*'

Remove .DS_Store files and __MACOSX directories

find . \( -type f -name '.DS_Store' -o -type d -name '__MACOSX' \) -exec rm -rf {} +

Plus vs semicolon

$ find . -name '*.c' -exec echo Found: {} +
Found: ./dev/src/main.c ./dev/src/func.c

$ find . -name '*.c' -exec echo Found: {} \;
Found: ./dev/src/main.c
Found: ./dev/src/func.c

Operator precedence

-a takes precedence over -o.

Global options

Apparently, find distinguishes between global options (such as -maxdepth, -xdev, -noleaf …) and non option arguments (such as -type) that are used in expressions.
It seems that the global options must precede the non option arguments. find . -type d maxdepth 1 would consequently give the following warning: you have specified the -maxdepth option after a non-option argument -type, but options are not positional (-maxdepth affects tests specified before it as well as those specified after it). Please specify options before other arguments.
Switching -maxdepth and -type makes the warning go away.

Finding block devices

Block devices can be identified with
$ find /dev -b

-H, -L, -P

-H, -L and -P controls the treatment of symbolic links:
-P Never follow symbolic links (the default behavior)
-L Follow symbolic links. Affects the -type predicate. Compare with the -follow option which takes effect where it appears.
-H Do not follow symboic links except when processing the command line arguments.

-D debug-options

-D allows to define debug options. These are specified separated by commas:
exec Show diagnostic information relating to -exec, -execdir, -ok and -okdir
opt Prints diagnostic information relating to the optimisation of the expression tree; see the -O option.
rates Prints a summary indicating how often each predicate succeeded or failed.
search Navigate the directory tree verbosely.
stat Print messages as files are examined with the stat and lstat system calls. The find program tries to minimise such calls.
tree Show the expression tree in its original and optimised form.
all Enable all of the other debug options (but help).
help Explain the debugging options.

-Olevel

-Olevel specifies the level of query optimization.
level can be set to one of the following values:
0 Equivalent to 1
1 Default value: Expressions based only on the name of files are evaluated first.
2 Evaluate -type and -xtype after file-name tests
3 Full cost based query optimizer

See also

The shell command locate.
https://github.com/ReneNyffenegger/shell-commands/tree/master/find
Perl module File::Find
Shell commands

Windows

A very cheap and amateurish equivalent of find in cmd.exe is forfiles.
The command line utilities find.exe and findstr.exe.

Index