= 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 == `find(1)` searches a directory for any files that match patterns and/or rules. To search for files by name, try: {{{ find somedir -name '*.zip' }}} The pattern is a glob shell expression, so options available are: + `?` as a wildcard + `*` as zero or more wildcards + character ranges like `[0-9]` It is ''not'' a regular expression pattern. Furthermore, note that the pattern is checked against the basename of the file; the directory components of the path are not checked. As a result, the only file that can ever match a pattern that includes a `/` is the root directory itself. === Search by File Type === To search for only files, try: {{{ find somedir -name '*.zip' -type f }}} Conversely, use `-type d` to search for only directories. === Search by File Ownership === To search for files by ownership, try: {{{ find somedir -user foo -exec chown bar {} \; }}} To search for files by group, try: {{{ find somedir -group foo -exec chgrp bar {} \; }}} === Search by File Permissions === To search for files by permissions, try: {{{ find somedir -type d -perm 755 }}} Conversely, to search for files with ''any other'' permissions, try: {{{ find somedir -type f -not -perm 644 -exec chmod 644 {} \; }}} === Command Execution === `find(1)` can execute a command on all matching files. 1. The `-exec` flag consumes everything following the flag up to an escaped delimiter, i.e. `\;`. 2. If that string contains a `{}`, that is expanded into the matching filename. * Note that there should only be one instance of `{}` in the string. Behavior for additional instances is undefined, non-portable, and unsupported. 3. The string is then evaluated as a command and executed in a subshell. * Note then that any environmental variables and functions are not shared. Try: {{{ find somedir -name '*.min.js' -exec cp {} ../production/ \; }}} Multiple commands can be chained, i.e. the second command only executes if the first command exits with a success code (0). {{{ find somedir -name '' -exec grep -F '' --quiet {} \; -exec cp {} ../production/ \; }}} === Programming 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 for `-exec` flags also operate in the working directory. These details can be inconvenient for whenever commands depend on proximate files, or for when the output will be parsed as text data. 1. Some issues can be alleviated by always calling with an absolute directory. Try: {{{ find "$(realpath somedir)" }}} 2. Other issues can be alleviated by always calling with the current directory. Try: {{{ cd somedir && find . }}} 2. Some implementations support `-execdir`. 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. * This inconsistency in behavior can lead to subtle issues. Use with caution, and consider adding a `-type f` pattern as well. More generally, this is a code smell; consider redesigning the approach. ---- == See also == [[https://man.archlinux.org/man/find.1|find(1)]] ---- CategoryRicottone