Find
find(1) is a file finder.
Contents
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.
The -exec flag consumes everything following the flag up to an escaped delimiter, i.e. \;.
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.
- 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 '<!--nomin-->' --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.
- Some issues can be alleviated by always calling with an absolute directory. Try:
find "$(realpath somedir)"
- Other issues can be alleviated by always calling with the current directory. Try:
cd somedir && find .
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.