# find — Search Files and Directories in a Directory Tree

> Practical guide to find — search files and directories by name, type, size, time and permissions, and act on the matches directly.

Source: https://www.jpkc.com/db/en/cheatsheets/files-text/find/

<!-- PROSE:intro -->
find walks entire directory trees and filters files and directories by name, type, size, timestamp, permissions and much more – and then acts on the matches directly. Instead of only printing paths, you attach arbitrary actions via `-exec`, `-delete` or a pipe to `xargs`. That is exactly where the tool gets sharp: `find … -delete` and `find … -exec rm` delete recursively and irreversibly, so test every destructive search with `-print` first. For filenames containing spaces or special characters, protect yourself with `-print0 | xargs -0` or `-exec … {} +`. This guide walks you through the expressions you actually reach for daily, from a simple name search to filtered bulk processing.
<!-- PROSE:intro:end -->

## Basic Search

`find <path>` — List all files and directories recursively under the given path.

```bash
find /home/user/projects/
```

`find .` — List all files and directories recursively under the current directory.

`find <path> -maxdepth <n>` — Limit the search depth to n levels below the starting point.

```bash
find . -maxdepth 2
```

`find <path> -mindepth <n>` — Skip the first n levels and only return results deeper than that.

```bash
find . -mindepth 2
```

`find <path1> <path2>` — Search in multiple directories at once.

```bash
find /var/log /tmp -name '*.log'
```

## Search by Name

`find <path> -name '<pattern>'` — Find files matching a name pattern (case-sensitive, supports wildcards).

```bash
find . -name '*.js'
```

`find <path> -iname '<pattern>'` — Find files matching a name pattern (case-insensitive).

```bash
find . -iname '*.jpg'
```

`find <path> -name '<pattern>' -not -name '<pattern>'` — Find files matching one pattern but not another.

```bash
find . -name '*.js' -not -name '*.min.js'
```

`find <path> -path '<pattern>'` — Match against the full path, not just the filename.

```bash
find . -path '*/src/*.ts'
```

`find <path> -regex '<pattern>'` — Match filenames using a regular expression (matches the whole path).

```bash
find . -regex '.*\.(js\|ts)$'
```

`find <path> -iregex '<pattern>'` — Match filenames using a case-insensitive regular expression.

```bash
find . -iregex '.*\.jpe?g$'
```

## Search by Type

`find <path> -type f` — Find regular files only.

```bash
find /var/log -type f -name '*.log'
```

`find <path> -type d` — Find directories only.

```bash
find . -type d -name 'node_modules'
```

`find <path> -type l` — Find symbolic links only.

```bash
find /usr/bin -type l
```

`find <path> -type f -empty` — Find empty files (zero bytes).

```bash
find /tmp -type f -empty
```

`find <path> -type d -empty` — Find empty directories.

```bash
find . -type d -empty
```

## Search by Size

`find <path> -size +<n>M` — Find files larger than n megabytes.

```bash
find / -size +100M
```

`find <path> -size -<n>k` — Find files smaller than n kilobytes.

```bash
find . -size -10k
```

`find <path> -size <n>c` — Find files of exactly n bytes.

```bash
find . -size 0c
```

`find <path> -size +<n>G` — Find files larger than n gigabytes.

```bash
find / -type f -size +1G
```

`find <path> -size +<min>M -size -<max>M` — Find files within a size range.

```bash
find . -type f -size +10M -size -100M
```

## Search by Time

`find <path> -mtime -<n>` — Find files modified in the last n days.

```bash
find . -mtime -7
```

`find <path> -mtime +<n>` — Find files modified more than n days ago.

```bash
find /var/log -mtime +30
```

`find <path> -mmin -<n>` — Find files modified in the last n minutes.

```bash
find . -mmin -60
```

`find <path> -atime -<n>` — Find files accessed in the last n days.

```bash
find . -atime -7
```

`find <path> -ctime -<n>` — Find files whose status (metadata) changed in the last n days.

```bash
find . -ctime -1
```

`find <path> -newer <reference>` — Find files modified more recently than a reference file.

```bash
find . -newer /tmp/timestamp.txt
```

`find <path> -newermt '<date>'` — Find files modified after a specific date (GNU find).

```bash
find . -newermt '2025-01-01'
```

`find <path> -not -newermt '<date>'` — Find files modified before a specific date.

```bash
find . -type f -not -newermt '2024-06-01'
```

## Search by Permissions & Ownership

`find <path> -perm <mode>` — Find files with exactly the specified permissions.

```bash
find . -perm 644
```

`find <path> -perm -<mode>` — Find files where all specified permission bits are set.

```bash
find . -perm -u+x
```

`find <path> -perm /<mode>` — Find files where any of the specified permission bits are set.

```bash
find . -perm /o+w
```

`find <path> -user <username>` — Find files owned by a specific user.

```bash
find /home -user www-data
```

`find <path> -group <groupname>` — Find files belonging to a specific group.

```bash
find /var -group staff
```

`find <path> -nouser` — Find files not owned by any known user.

`find <path> -nogroup` — Find files not belonging to any known group.

`find <path> -perm -4000` — Find files with the SUID bit set.

```bash
find /usr -perm -4000 -type f
```

`find <path> -perm -2000` — Find files with the SGID bit set.

```bash
find /usr -perm -2000 -type f
```

## Actions

`find <path> <expression> -print` — Print the full path of each match (default action).

```bash
find . -name '*.log' -print
```

`find <path> <expression> -print0` — Print results separated by null character (safe for filenames with spaces).

```bash
find . -name '*.txt' -print0 | xargs -0 wc -l
```

`find <path> <expression> -ls` — Print results in ls -l format with detailed file info.

```bash
find /tmp -type f -mtime -1 -ls
```

`find <path> <expression> -delete` — Delete all matching files (use with caution, test with -print first).

```bash
find /tmp -type f -name '*.tmp' -mtime +7 -delete
```

`find <path> <expression> -exec <command> {} \;` — Execute a command for each match. {} is replaced by the filename.

```bash
find . -name '*.log' -exec rm {} \;
```

`find <path> <expression> -exec <command> {} +` — Execute a command with all matches as arguments (faster than \;).

```bash
find . -name '*.txt' -exec grep -l 'TODO' {} +
```

`find <path> <expression> -execdir <command> {} \;` — Execute a command in the directory of each match (safer than -exec).

```bash
find . -name '*.bak' -execdir rm {} \;
```

`find <path> <expression> -ok <command> {} \;` — Like -exec but ask for confirmation before each execution.

```bash
find . -name '*.tmp' -ok rm {} \;
```

## Logical Operators

`find <path> -name '<a>' -and -name '<b>'` — Match files satisfying both conditions (AND, default when juxtaposed).

```bash
find . -name '*.js' -and -size +100k
```

`find <path> -name '<a>' -or -name '<b>'` — Match files satisfying either condition (OR).

```bash
find . -name '*.jpg' -or -name '*.png'
```

`find <path> -not <expression>` — Negate an expression (NOT).

```bash
find . -type f -not -name '*.log'
```

`find <path> \( <expr1> -or <expr2> \) -and <expr3>` — Group expressions with escaped parentheses for precedence.

```bash
find . \( -name '*.js' -or -name '*.ts' \) -and -size +10k
```

## Output & Formatting

`find <path> -printf '<format>'` — Print results in a custom format (GNU find).

```bash
find . -type f -printf '%s %p\n'
```

`find <path> -printf '%T+ %p\n'` — Print modification time and path for each file.

```bash
find . -type f -printf '%T+ %p\n' | sort -r | head -20
```

`find <path> -printf '%s\t%p\n'` — Print file size (bytes) and path, tab-separated.

```bash
find . -type f -printf '%s\t%p\n' | sort -rn | head -10
```

`find <path> -fprintf <file> '<format>'` — Write formatted output to a file instead of stdout.

```bash
find /var/log -type f -fprintf /tmp/logfiles.txt '%p\n'
```

## Excluding Directories

`find <path> -name '<dir>' -prune -o <expression> -print` — Exclude a directory from the search using -prune.

```bash
find . -name 'node_modules' -prune -o -name '*.js' -print
```

`find <path> -path '<pattern>' -prune -o <expression> -print` — Exclude directories matching a path pattern.

```bash
find . -path './.git' -prune -o -type f -print
```

`find <path> \( -name '<a>' -o -name '<b>' \) -prune -o <expression> -print` — Exclude multiple directories from the search.

```bash
find . \( -name 'node_modules' -o -name '.git' \) -prune -o -type f -name '*.ts' -print
```

## Practical Examples

`find . -type f -name '*.log' -mtime +30 -delete` — Delete log files older than 30 days.

`find . -type f -name '*.php' -exec grep -l '<pattern>' {} +` — Find PHP files containing a specific string.

```bash
find . -type f -name '*.php' -exec grep -l 'TODO' {} +
```

`find . -type f -exec chmod 644 {} +` — Set permissions to 644 for all regular files.

`find . -type d -exec chmod 755 {} +` — Set permissions to 755 for all directories.

`find . -type f -name '*.txt' -print0 | xargs -0 tar -czf texts.tar.gz` — Create a tar archive of all .txt files (handles spaces in names).

`find . -type f -printf '%s\t%p\n' | sort -rn | head -20` — Find the 20 largest files in a directory tree.

`find . -type f -name '*.jpg' -exec cp {} /backup/images/ \;` — Copy all JPEG files to a backup directory.

`find . -maxdepth 1 -type f -name '*.bak' -exec mv {} {}.old \;` — Rename all .bak files by appending .old in the current directory.

`find . -name '*.orig' -o -name '*.bak' -o -name '*~' | xargs rm -f` — Remove common backup and temporary files.

`find /var/log -type f -size +50M -exec ls -lh {} +` — List large log files with human-readable sizes.

<!-- PROSE:outro -->
## Conclusion

find is one of the most powerful tools on the command line: with combinable tests for name, type, size, time and permissions, you narrow down even huge directory trees precisely and process the matches in one pass. That same power makes find dangerous, though – `-delete` and `-exec rm … {} +` delete recursively and without asking; test every destructive search with `-print` first, and for filenames with spaces use `-print0 | xargs -0` or `-exec … {} +` consistently rather than a plain pipe. Note as well that `-printf`/`-fprintf`, `-regex` and `-newermt` are GNU extensions: the `find` on macOS and BSD does not know `-printf` and behaves differently for some options.

## Further Reading

- [GNU Findutils Manual](https://www.gnu.org/software/findutils/manual/html_mono/find.html) – complete official reference for all find options
- [find(1) manual page](https://man7.org/linux/man-pages/man1/find.1.html) – the Linux manual page for find
<!-- PROSE:outro:end -->

## Related Commands

- [grep](https://www.jpkc.com/db/en/cheatsheets/files-text/grep/) – searches file contents for patterns and regular expressions
- [xargs](https://www.jpkc.com/db/en/cheatsheets/files-text/xargs/) – builds and runs command lines from find's output
- [ls](https://www.jpkc.com/db/en/cheatsheets/files-text/ls/) – lists directory contents with details on permissions and size

