Size: 1256
Comment: Link
|
Size: 3890
Comment: Rewrite
|
Deletions are marked like this. | Additions are marked like this. |
Line 21: | Line 21: |
`find(1)` identifies files and, by default, simply prints them. | `find(1)` searches a directory for any files that match patterns and/or rules. |
Line 23: | Line 23: |
`find(1)` can alternatively execute a command on the file name. Note that this occurs in a subshell, so functions and environment variables are not accessible to the command. | To search for files by name, try: |
Line 26: | Line 26: |
find . --exec mv ../backup/{} \; | 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 {} \; |
Line 31: | Line 69: |
=== File Name === | === Search by File Permissions === |
Line 33: | Line 71: |
To find all files with a name matching a pattern, try: | To search for files by permissions, try: |
Line 36: | Line 74: |
find . -name '*.pyc' -exec rm {} \; | 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 {} \; |
Line 41: | Line 85: |
=== File Ownership === | === Command Execution === |
Line 43: | Line 87: |
To find all files owned by user `foo`, try: | `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: |
Line 46: | Line 98: |
find . -user foo -exec chown bar {} \; | find somedir -name '*.min.js' -exec cp {} ../production/ \; |
Line 49: | Line 101: |
To find all files in the group `foo`, try: | Multiple commands can be chained, i.e. the second command only executes if the first command exits with a success code (0). |
Line 52: | Line 104: |
find . -group foo -exec chgrp bar {} \; | find somedir -name '' -exec grep -F '<!--nomin-->' --quiet {} \; -exec cp {} ../production/ \; |
Line 57: | Line 109: |
=== File Permissions === | === Programming Tips === |
Line 59: | Line 111: |
To find all files with some permission level, try: | `find(1)` operates from the working directory and prints filenames accordingly. That is... |
Line 61: | Line 113: |
{{{ find . -type d -perm 755 }}} |
* 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. |
Line 65: | Line 117: |
Conversely, to find all files with any other permission level, try: | Furthermore, any subshells started for `-exec` flags also operate in the working directory. |
Line 67: | Line 119: |
{{{ find . -type f -not -perm 644 -exec chmod 644 {} \; }}} |
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. |
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.