Differences between revisions 2 and 6 (spanning 4 versions)
Revision 2 as of 2023-07-23 19:21:44
Size: 1182
Comment:
Revision 6 as of 2024-12-28 15:42:20
Size: 4519
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)` 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.
Basic usage:
Line 26: Line 24:
find . --exec mv ../backup/{} \; 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]
Line 31: Line 62:
=== File Name === === Command Execution ===
Line 33: Line 64:
To find all files with a name matching a pattern, try: `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:
Line 36: Line 76:
find . -name '*.pyc' -exec rm {} \; find somedir -name '' -exec grep --fixed-strings '<!--nomin-->' --quiet {} \;
Line 38: Line 78:

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/ \;
}}}

----
Line 41: Line 91:
=== File Ownership === == Tips ==
Line 43: Line 93:
To find all files owned by user `foo`, try: `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:
Line 46: Line 112:
find . --user foo -exec chown bar {} \; while IFS= read -r -d '' file; do
    echo "$file"
done < <(find . -name '*.zip' -print0)
Line 49: Line 117:
To find all files in the group `foo`, try: {{{
find . -name '*.zip' -print0 | xargs -0 echo
}}}
Line 51: Line 121:
{{{
find . --group foo -exec chgrp bar {} \;
}}}
----
Line 57: Line 125:
=== File Permissions === == See also ==
Line 59: Line 127:
To find all files with some permission level, try:

{{{
find . --type d --perm 755
}}}

Conversely, to find all files with any other permission level, try:

{{{
find . --type f --not --perm 644 --exec chmod 644 {} \;
}}}
[[https://man.archlinux.org/man/find.1|find(1)]]

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 '<!--nomin-->' --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

find(1)


CategoryRicottone

Find (last edited 2024-12-28 15:42:20 by DominicRicottone)