Linux Terminal Command: find (Recursive Filesystem Search)

The find command is one of the most powerful system administration utilities in Linux. It recursively traverses directory trees, finds files and directories that match complex, multi-layered criteria, and allows you to execute shell commands directly on the results.

In this tutorial, we will explore the complete syntax of find, understand its filtering systems, and cover advanced execution recipes.


Concept & Explanation

Unlike commands like locate which query static cached databases, find queries the filesystem in real time.

The basic syntax structure of find is:

find [search-paths] [filters/expressions] [actions]

By default, if you don’t specify a path, find uses the current directory (.). If you don’t specify an action, it defaults to printing the matches (-print).


1. Filtering Criteria (Filters & Expressions)

A. Filtering by Name and Case

find . -name "*.config"
find /etc -iname "*.ini"

B. Filtering by File Type (-type)

Restricts search results to specific types of filesystem objects:

# Find directories only
find ~/projects -type d -name "src"

C. Filtering by Size (-size)

Specify file sizes using suffixes like k (kilobytes), M (megabytes), or G (gigabytes). Use + for larger than, and - for smaller than:

# Find files larger than 100MB
find /var/log -type f -size +100M

# Find empty files (0 bytes)
find . -type f -empty

D. Filtering by Time (Modified, Accessed, Changed)

Linux tracks three file timestamps, and you can query them in days (-mtime, -atime, -ctime) or minutes (-mmin, -amin, -cmin):

# Find files modified in the last 24 hours (1 day)
find . -type f -mtime -1

# Find files modified more than 10 days ago
find /tmp -type f -mtime +10

# Find logs modified in the last 30 minutes
find /var/log -type f -mmin -30

2. Logical Operators

You can chain multiple criteria together using logical operators:

# Find files that are either markdown (.md) OR text (.txt)
find . -type f \( -name "*.md" -o -name "*.txt" \)

# Find files that do NOT end in .git
find . -type f -not -path "*/.git/*"

3. Action Execution (-exec and -delete)

Finding files is only half the battle. Often you want to do something to them.

A. Deleting Files Safely (-delete)

You can delete matched files directly.

find /tmp -type f -name "*.tmp" -delete

[!CAUTION] Test your query first! Run find /tmp -type f -name "*.tmp" to inspect matches before appending -delete, as deletion is permanent.

B. Executing Commands on Matches (-exec)

The -exec flag runs a shell command on every matched item. The placeholder {} is replaced by the current file path, and the command must end with an escaped semicolon \;.

# Run command once per file
find . -name "*.sh" -exec chmod +x {} \;

If you have thousands of files, running the command once per file creates a lot of process overhead. You can use the + terminator to group the files and run the command once with all file names as arguments (like xargs does):

# Efficiently search for text inside all matched files
find ./src -type f -name "*.js" -exec grep "TODO" {} +

⚙️ Warning & Common Pitfalls

[!WARNING] Quote your Wildcards

If you run find . -name *.txt without quoting, the shell will expand *.txt to any matching files in the current directory before running find. If you have a.txt and b.txt in your active folder, the command will expand to: find . -name a.txt b.txt (which is a syntax error).

Always wrap wildcard patterns in quotes: find . -name "*.txt"


Here are some related posts on cli_tty1 you might want to check out: