= Find = '''`find(1)`''' is a file finder. <> ---- == Installation == `find(1)` will be pre-installed on any [[Linux]] or [[BSD]] operating system, as a POSIX utility. ---- == Usage == Basic usage: {{{ find . -name '*.zip' }}} The pattern is a glob shell expression, ''not'' a regular expression pattern. The options available are: * `?` as a wildcard * `*` as zero or more wildcards * character ranges like `[0-9]` But to ensure that the glob is not eagerly evaluated by the shell, the pattern must be quoted. Furthermore, note that the pattern is checked against the basename of the directory entry. The only possible match to a pattern that includes a `/` is the root directory itself. === Options === ||'''Options''' ||'''Meaning''' ||'''Example''' || ||`-name 'pattern'`||Filter to entries with a basename matching a pattern||`-name '*.zip'` || ||`-type [df]` ||Filter to files or directories ||`-type f` || ||`-user name` ||Filter to entries owned by a user ||`-user root` || ||`-group name` ||Filter to entries owned by a group ||`-group root` || ||`-perm octal` ||Filter to entries with specific permissions ||`-perm 775` || ||`-not` ||Invert a subsequent filter ||`-not -perm 775`|| ||`-mindepth int` ||Only search subdirectories some layers deep ||`-mindepth 1` || ||`-maxdepth int` ||Stop searching subdirectories at some layers deep ||`-maxdepth 1` || `-mindepth` and `-maxdepth` are global options, so must precede any other options. {{{ $ find . -name '*.txt' -maxdepth 1 find: warning: you have specified the global option -maxdepth after the argument -name, but global options are not positional, i.e., -maxdepth affects tests specified before it as well as those specified after it. Please specify global options before other arguments. $ find . -maxdepth 1 -name '*.txt' [trim] }}} === Command Execution === `find(1)` can execute a command on all still-matching files. 1. The `-exec` option consumes all subsequent arguments up to an escaped delimiter, i.e. `\;`. 2. If one of those arguments contains `{}`, that is expanded into the filename. * Note that there should only be one `{}`. Behavior for additional instances is undefined, non-portable, and unsupported. 3. The arguments are executed in a subshell. * Note then that any environmental variables and functions are not shared. 4. The return code of the subshell determines if the option is considered a match or non-match The `-exec` option can be used to implement custom filters. For example: {{{ find somedir -name '' -exec grep --fixed-strings '' --quiet {} \; }}} The `-exec` option can also be used for scripting, to execute some action on all matches. For example: Try: {{{ find somedir -name '*.min.js' -exec cp {} ../production/ \; }}} ---- == Tips == `find(1)` operates from the working directory and prints filenames accordingly. That is... * if called like `find .`, all filenames will be printed starting with `./`. * if called like `find ..`, all filenames will be printed starting with `../`. * if called with an absolute directory like `find /etc`, all filenames will be printed as absolute, too. Furthermore, any subshells started by the `-exec` option operate in the working directory. This can be tricky and inconvenient for scripting. Consider: 1. Always call with an absolute directory. For example: `find "$(realpath somedir) ...` 2. Change directory instead of passing a directory. For example: `cd somedir && find . ...` 3. Check if your `find(1)` implementation supports the `-execdir` option. This flag mirrors `-exec` except that... * if a file is matched, the execution occurs in the same directory as that file. * if a directory is matched, the execution occurs in the parent directory. `find(1)` should never be piped directly into another command. If the `-exec` option is insufficient, the safe ways to use the output of `find(1)` are: {{{ while IFS= read -r -d '' file; do echo "$file" done < <(find . -name '*.zip' -print0) }}} {{{ find . -name '*.zip' -print0 | xargs -0 echo }}} ---- == See also == [[https://man.archlinux.org/man/find.1|find(1)]] ---- CategoryRicottone