How to Find Files in Linux Using the find Command

Master the Linux find command with practical examples. Learn to search by name, size, date, permissions, owner, and content — and act on results automatically.

How to Find Files in Linux Using the find Command

The Linux find command searches the filesystem in real time for files and directories matching criteria you specify. Basic usage is find [directory] [criteria] — for example, find ~ -name "*.pdf" finds all PDF files in your home directory, and find /var/log -mtime -7 finds log files modified in the last 7 days. Unlike locate, which searches a database, find always reflects the current state of the filesystem and supports dozens of filtering options including name, size, type, date, permissions, and ownership.

Introduction: Your Most Precise Search Tool

Every Linux user eventually faces the same challenge: a file is somewhere on the system, but where? Maybe you downloaded something last week and cannot remember which directory it ended up in. Maybe you need to find every configuration file belonging to a specific application. Maybe you want to locate all log files older than 30 days so you can archive or delete them. Maybe you need to find every script that has world-writable permissions as part of a security audit.

For all of these tasks, Linux provides find — one of the most powerful and flexible commands in the entire Linux toolkit. Unlike graphical file search tools that rely on indexes or keyword searches, find searches the live filesystem directly, in real time, with precise filtering criteria. It finds files not just by name but by any combination of attributes: file type, size, modification date, permissions, ownership, content, and more. And crucially, it can act on the files it finds — running any command on each result automatically.

find has a reputation for complexity, and its syntax is different enough from most Linux commands to feel unfamiliar at first. But the complexity is in service of power — once you understand find‘s structure and its core options, it becomes one of those tools you reach for constantly, because it solves problems that nothing else addresses as precisely.

This article teaches find comprehensively, from basic name searches through complex multi-criteria queries to the powerful -exec option that transforms find into a batch processing engine. Every concept is illustrated with practical examples you can use immediately.

The find Command Structure

Before exploring individual options, understanding find‘s overall structure makes everything else clearer.

Basic Syntax

Bash
find [starting_point...] [expression]

The starting point is the directory (or directories) where the search begins. find descends recursively through all subdirectories from this point. If you omit the starting point, find uses the current directory.

The expression is the set of criteria and actions that determine what matches and what to do with matches. Expressions consist of:

  • Tests — conditions that each file must satisfy (name matches a pattern, size exceeds a threshold, etc.)
  • Actions — things to do with matching files (print them, delete them, execute a command)
  • Operators — logical connectors between tests and actions (AND, OR, NOT)

When no expression is given, find prints every file it encounters — equivalent to find -print.

How find Traverses the Filesystem

find starts at the specified directory and visits every file and directory within it, recursively. For each item it visits, it evaluates the expression. Items that satisfy all tests (or the overall logical expression) are matched and the specified action is taken. Items that do not satisfy the tests are silently skipped.

This traversal is depth-first by default — find explores each directory’s contents before moving to the next directory at the same level. The traversal is also thorough: find visits every item, with no index or cache. This is what makes find accurate (it always reflects the current state) but also what makes it slower than locate for simple name searches on large filesystems.

Basic Name Searches

The most common use of find is locating files by name.

Finding by Exact Name

Bash
$ find ~ -name "report.pdf"
/home/sarah/Documents/reports/report.pdf

The -name test matches files whose name exactly matches the pattern. The match is case-sensitive — report.pdf and Report.pdf are different names.

Finding with Wildcards

-name supports shell wildcards. Important: Always quote wildcard patterns to prevent the shell from expanding them before passing them to find.

Find all PDF files anywhere in your home directory:

Bash
$ find ~ -name "*.pdf"
/home/sarah/Documents/report.pdf
/home/sarah/Downloads/manual.pdf
/home/sarah/Projects/spec.pdf

Find files starting with “backup”:

Bash
$ find /var -name "backup*"

Find files with a specific extension pattern:

Bash
$ find ~/code -name "*.py"

Find files matching a specific naming pattern (date-prefixed files):

Bash
$ find ~/logs -name "2026-02-*"

Case-Insensitive Name Search

-iname works exactly like -name but matches regardless of case:

Bash
$ find ~ -iname "readme*"
/home/sarah/projects/website/README.md
/home/sarah/projects/app/readme.txt
/home/sarah/Downloads/Readme.html

This matches README.md, readme.txt, and Readme.html — all case variations.

Searching in Multiple Directories

Specify multiple starting points:

Bash
$ find ~/Documents ~/Downloads -name "*.pdf"

Search the entire filesystem (use with caution — can be slow and generates errors for inaccessible directories):

Bash
$ sudo find / -name "nginx.conf" 2>/dev/null<br>/etc/.nginx/nginx.conf<br>

The 2>/dev/null redirects error messages (like “Permission denied” for directories find cannot access) to null, keeping the output clean.

Filtering by File Type

find distinguishes between different types of filesystem objects, allowing you to limit searches to just files, just directories, or other specific types.

The -type Test

Bash
$ find ~ -type f -name "*.txt"    # Regular files only
$ find ~ -type d -name "backup*"  # Directories only
$ find ~ -type l                  # Symbolic links only

Type values:

  • f — regular file
  • d — directory
  • l — symbolic link
  • c — character device (in /dev)
  • b — block device (in /dev)
  • p — named pipe (FIFO)
  • s — socket

Practical Type Filtering

Find all directories named “node_modules” (to check disk space usage by JavaScript projects):

Bash
$ find ~ -type d -name "node_modules"
/home/sarah/projects/app1/node_modules
/home/sarah/projects/app2/node_modules

Find all symbolic links in /etc that might be broken:

Bash
$ find /etc -type l

Find all empty files (type f combined with -empty):

Bash
$ find ~/Downloads -type f -empty

Find all empty directories:

Bash
$ find ~/projects -type d -empty

Searching by Size

find can locate files based on their size, with support for common size units and comparison operators.

The -size Test

Bash
$ find ~ -size +100M      # Files LARGER than 100 megabytes
$ find ~ -size -10k       # Files SMALLER than 10 kilobytes
$ find ~ -size 1G         # Files EXACTLY 1 gigabyte (rarely useful)

Size units:

  • c — bytes (characters)
  • k — kilobytes (1024 bytes)
  • M — megabytes (1024 KB)
  • G — gigabytes (1024 MB)

Comparison operators:

  • +N — greater than N
  • -N — less than N
  • N (no sign) — exactly N (rounded to the nearest unit)

Practical Size Searches

Find large files consuming disk space in your home directory:

Bash
$ find ~ -type f -size +500M
/home/sarah/Videos/vacation.mkv
/home/sarah/.local/share/steam/steamapps/game.pak

Find all files larger than 1 GB on the entire system:

Bash
$ sudo find / -type f -size +1G 2>/dev/null

Find suspiciously small (possibly empty or corrupted) files in a directory:

Bash
$ find ~/data -type f -size -100c

Combine size with type to find large log files specifically:

Bash
$ find /var/.log -type f -size +50M
/var/.log/syslog
/var/.log/kern.log.1

Searching by Modification Time

Time-based searches are among the most practically useful find capabilities — finding recently changed files, locating old files for archiving, or identifying files modified during a specific window.

Time-Based Tests

-mtime N — files modified exactly N days ago (rarely useful) -mtime +N — files modified MORE than N days ago (older than N days) -mtime -N — files modified LESS than N days ago (newer than N days)

Days are measured in 24-hour periods from the current time.

Bash
$ find ~/Documents -mtime -7     # Modified in the last 7 days
$ find /var/.log -mtime +30       # Not modified in over 30 days
$ find ~/Downloads -mtime +90    # Downloads older than 90 days

-mmin N — modification time in minutes (for finer resolution):

Bash
$ find /tmp -mmin -60            # Modified in the last hour
$ find ~/Desktop -mmin +30       # Not modified in the last 30 minutes

Access Time and Change Time

find supports three timestamps for each file:

-mtime — modification time: when the file’s content was last changed -atime — access time: when the file was last read -ctime — change time: when the file’s metadata (permissions, ownership) was last changed

Access time (-atime) is often unreliable because many filesystems mount with noatime to reduce disk writes. Change time (-ctime) is useful for finding files whose permissions or ownership were recently modified.

Comparing Against a Reference File

-newer file matches files modified more recently than the reference file:

Bash
$ find ~/projects -newer ~/projects/last_backup.txt

This finds all files in your projects directory that have been modified since your last backup marker file was created — exactly what you need to know what needs backing up.

Searching by Permissions

find‘s permission-based tests are powerful for security auditing and permission management.

The -perm Test

Exact permission match:

Bash
$ find ~ -perm 644          # Files with EXACTLY 644 permissions
$ find ~ -perm 755          # Files with EXACTLY 755 permissions

At-least permissions (slash mode):

Bash
$ find ~ -perm /o+w         # Files writable by others (world-writable)
$ find ~ -perm /a+x         # Files executable by anyone

The / prefix means “at least these permissions are set” — any file where at least one of the specified bits is set matches.

All-of permissions (dash mode):

Bash
$ find ~ -perm -644         # Files where owner has rw AND others have r (minimum)
$ find ~ -perm -u+x         # Files executable by their owner

The - prefix means “all of these bits must be set.”

Critical Security Searches

Find all SetUID programs (programs that run as their owner when executed):

Bash
$ find / -perm -4000 -type f 2>/dev/null
/usr/bin/passwd
/usr/bin/sudo
/usr/bin/su

Find all SetGID programs:

Bash
$ find / -perm -2000 -type f 2>/dev/null

Find world-writable files (potential security concern):

Bash
$ find / -perm /o+w -type f 2>/dev/null | grep -v proc

Find world-writable directories:

Bash
$ find / -perm /o+w -type d 2>/dev/null | grep -v proc

Important: Running these searches on a new system and keeping a baseline lets you detect if new SetUID files or world-writable locations appear later — which could indicate a compromise.

Searching by Ownership

find can locate files by their owner or associated group.

The -user and -group Tests

Find all files owned by a specific user:

Bash
$ find /home -user sarah
$ find /var/www -user www-data

Find all files belonging to a specific group:

Bash
$ find /projects -group developers

Find files NOT owned by root in system directories (potential intrusion indicator):

Bash
$ find /usr/bin -not -user root -type f

Find files owned by a user who no longer exists (orphaned files with numeric UID):

Bash
$ find /home -nouser

-nouser matches files whose owner UID does not correspond to any user in /etc/.passwd. Similarly, -nogroup matches files with no valid group.

Combining Owner and Permission Checks

Find SetUID files not owned by root (particularly suspicious security-wise):

Bash
$ find / -perm -4000 -not -user root -type f 2>/dev/null

Combining Multiple Criteria with Logical Operators

The real power of find emerges when you combine multiple tests with logical operators.

Implicit AND

When you list multiple tests without operators, they are implicitly joined by AND — all tests must be satisfied:

Bash
$ find ~/Documents -type f -name "*.pdf" -size +1M

This finds regular files (-type f) with a .pdf extension (-name "*.pdf") that are larger than 1 MB (-size +1M). All three conditions must be true.

Bash
$ find /var/.log -type f -name "*.log" -mtime +30

Log files older than 30 days — both conditions required.

Explicit OR with -o

Use -o for logical OR — either condition satisfies the match:

Bash
$ find ~ -name "*.jpg" -o -name "*.jpeg"

Finds files ending in either .jpg or .jpeg.

Bash
$ find ~/projects -name "*.py" -o -name "*.js" -o -name "*.ts"

Finds Python, JavaScript, or TypeScript files.

Important grouping with OR: When using -o, use parentheses to group conditions correctly (escape them in bash):

Bash
$ find ~ \( -name "*.jpg" -o -name "*.jpeg" \) -size +5M

Without the parentheses, the -size +5M test would only apply to the .jpeg condition, not to the entire OR expression. The backslash-escaped parentheses tell find to group the name conditions.

Negation with -not or !

Bash
$ find ~/Documents -not -name "*.pdf"     # All files EXCEPT PDFs
$ find /tmp -not -user sarah              # Files NOT owned by sarah
$ find ~ -type f ! -name "*.py"          # Not Python files (! is equivalent to -not)

Complex Combined Examples

Find large images (JPEG or PNG) modified in the last week:

Bash
$ find ~/Pictures \( -name "*.jpg" -o -name "*.png" \) -size +2M -mtime -7

Find Python files NOT in node_modules or .git directories:

Bash
$ find ~/projects -name "*.py" -not -path "*/node_modules/*" -not -path "*/.git/*"

Find configuration files modified in the last hour (after a configuration change):

Bash
$ find /etc -type f -name "*.conf" -mmin -60

Controlling Depth with -maxdepth and -mindepth

By default, find recurses infinitely deep. The depth options control how many directory levels are searched.

-maxdepth: Limit Search Depth

Bash
$ find ~ -maxdepth 1 -name "*.txt"

Only searches in ~ itself, not any subdirectories. Equivalent to ls ~/*.txt.

Bash
$ find ~ -maxdepth 2 -type d

Lists all directories within your home directory and one level deeper — useful for a quick overview of your project structure.

Bash
$ find /etc -maxdepth 1 -name "*.conf" -type f

Finds configuration files directly in /etc without descending into /etc‘s subdirectories.

-mindepth: Skip Shallow Matches

Bash
$ find ~ -mindepth 2 -name "*.log"

Skips log files directly in ~ and only finds them starting from subdirectories two levels deep.

Combining maxdepth and mindepth

Bash
$ find /var/.log -mindepth 1 -maxdepth 2 -name "*.log"

Searches log files in /var/.log‘s immediate subdirectories only, not in /var/.log itself or deeper than one level of subdirectory.

Pruning Directories from Search

When searching large directory trees, excluding certain directories dramatically speeds up the search and reduces noise.

-prune: Skip a Directory

Bash
$ find ~ -name ".git" -prune -o -name "*.py" -print

This is one of find‘s more complex patterns. The expression says: if the file is named .git then prune it (skip it and do not descend into it), OR print the file if it matches *.py. The -o creates an OR condition — either prune or print.

A simpler alternative using -not -path:

Bash
$ find ~ -name "*.py" -not -path "*/.git/*"

Common Directory Exclusions

Exclude multiple directories from a search:

Bash
$ find ~/projects \
    -not -path "*/node_modules/*" \
    -not -path "*/.git/*" \
    -not -path "*/__pycache__/*" \
    -name "*.py"

The backslash-newline continuation allows long commands to span multiple lines for readability.

Taking Action with -exec and -execdir

find becomes a batch processing powerhouse through its -exec option, which runs a command on each file found.

The -exec Action

Bash
$ find [criteria] -exec command {} \;

The {} placeholder is replaced by the path of each found file. The \; marks the end of the command (the semicolon must be escaped or quoted to prevent the shell from interpreting it).

Delete all .tmp files:

Bash
$ find ~/cache -name "*.tmp" -exec rm {} \;

Show detailed info for large files:

Bash
$ find ~ -size +100M -exec ls -lh {} \;

Copy found files to a backup directory:

Bash
$ find ~/Documents -name "*.docx" -exec cp {} ~/backup/ \;

Change permissions on all shell scripts:

Bash
$ find ~/scripts -name "*.sh" -exec chmod 755 {} \;

Open each found file in your text editor (interactive):

Bash
$ find ~ -name "TODO.txt" -exec nano {} \;

Using + Instead of ; for Efficiency

The \; variant runs the command once per file. The + variant passes all matching files to the command at once (like xargs), which is much faster when the command can handle multiple arguments:

Bash
$ find ~/scripts -name "*.sh" -exec chmod 755 {} +

This runs chmod 755 file.1.sh file.2.sh file.3.sh (all at once) rather than chmod 755 file.1.sh then chmod 755 file.2.sh etc. For commands that accept multiple files, + is significantly faster.

-execdir: Safer Execution in File’s Directory

-execdir is like -exec but runs the command from the directory containing the found file, with the filename as ./filename rather than the full path:

Bash
$ find ~/projects -name "*.py" -execdir python3 -m py_compile {} \;

-execdir is safer because it avoids potential PATH manipulation attacks and ensures the command runs in the correct context for the file.

The -ok Action: Interactive Confirmation

-ok works like -exec but asks for confirmation before running the command on each file:

Bash
$ find ~/Downloads -name "*.zip" -mtime +365 -ok rm {} \;
rm ... '/home/sarah/Downloads/old_software.zip'? y
rm ... '/home/sarah/Downloads/archive.zip'? n

Useful when you want to review each match before acting on it.

Using find with xargs

For complex operations or when -exec is not flexible enough, piping find output to xargs provides additional power.

Basic xargs Usage

Bash
$ find ~/Documents -name "*.pdf" | xargs ls -lh

xargs reads its standard input (the list of filenames from find) and passes them as arguments to the specified command. This is equivalent to -exec ls -lh {} + but allows more complex command construction.

Handling Filenames with Spaces

Filenames with spaces break naive xargs usage because xargs splits on whitespace. The correct approach uses null delimiters:

Bash
$ find ~ -name "*.txt" -print0 | xargs -0 grep -l "TODO"

-print0 (with zero) makes find separate filenames with null characters instead of newlines. -0 tells xargs to split on null characters. This handles filenames containing spaces, newlines, and other unusual characters correctly.

Always use -print0 and xargs -0 in scripts where filenames may contain spaces.

Parallel Execution with xargs

xargs -P N runs N instances of the command in parallel — dramatically faster for CPU-intensive operations:

Bash
$ find ~/images -name "*.png" -print0 | xargs -0 -P 4 -I{} convert {} -resize 800x600 {}_resized.png

This converts PNG images in parallel using 4 simultaneous processes.

Practical find Recipes

These ready-to-use commands address common real-world scenarios.

Disk Space Management

Find the 20 largest files in your home directory:

Bash
$ find ~ -type f -printf "%s %p\n" | sort -rn | head -20 | awk '{print $1/1024/1024 "MB " $2}'

Find all files larger than 100MB:

Bash
$ find ~ -type f -size +100M -exec ls -lh {} \;

Find and delete empty files:

Bash
$ find ~/Downloads -type f -empty -delete

Find and delete empty directories:

Bash
$ find ~/projects -type d -empty -delete

Log File Management

Find log files older than 30 days:

Bash
$ find /var/.log -type f -name "*.log" -mtime +30

Compress old log files:

Bash
$ find /var/.log -type f -name "*.log" -mtime +7 -exec gzip {} \;

Find and delete old compressed logs:

Bash
$ find /var/.log -type f -name "*.gz" -mtime +90 -delete

Security Auditing

Find all SetUID/SetGID executables:

Bash
$ find / \( -perm -4000 -o -perm -2000 \) -type f 2>/dev/null

Find world-writable files outside /tmp:

Bash
$ find / -perm -o+w -type f -not -path "/tmp/*" -not -path "/proc/*" 2>/dev/null

Find files recently modified in sensitive directories:

Bash
$ find /etc /usr/bin /usr/sbin -mtime -1 -type f 2>/dev/null

Development Workflows

Count lines of code in all Python files (excluding virtualenv and git):

Bash
$ find . -name "*.py" -not -path "./.venv/*" -not -path "./.git/*" | xargs wc -l | tail -1

Find all TODO comments in source code:

Bash
$ find ~/projects -name "*.py" -exec grep -ln "TODO\|FIXME\|HACK" {} \;

Find configuration files that need updating (older than the template):

Bash
$ find /etc -name "*.conf" -newer /etc/.template.conf

find vs. locate: Choosing the Right Tool

Featurefindlocate
Search methodLive filesystem traversalPre-built database
SpeedSlower (thorough)Much faster
AccuracyAlways currentMay be out of date
Criteria typesName, size, date, permissions, owner, type, contentName/path only
Can act on resultsYes (-exec, -delete)No
Requires database updateNosudo updatedb
Root requiredOnly for restricted dirsNo
Best forComplex criteria, accurate results, acting on filesQuick name searches

Use locate when you just need to find where a file is by name and speed matters.

Use find when you need precision, current results, multiple criteria, or want to act on the results.

find Quick Reference

TaskCommand
Find by name (case-sensitive)find ~ -name "*.pdf"
Find by name (case-insensitive)find ~ -iname "readme*"
Find regular files onlyfind ~ -type f -name "*.txt"
Find directories onlyfind ~ -type d -name "backup*"
Find by size (larger than)find ~ -size +100M
Find recently modifiedfind ~ -mtime -7
Find old filesfind /var/log -mtime +30
Find by ownerfind /home -user sarah
Find world-writablefind ~ -perm /o+w -type f
Find SetUID filesfind / -perm -4000 -type f
Exclude directoryfind ~ -not -path "*/node_modules/*"
Limit depthfind ~ -maxdepth 2 -name "*.conf"
Execute command on resultsfind ~ -name "*.sh" -exec chmod +x {} \;
Delete matching filesfind ~/cache -name "*.tmp" -delete
Handle spaces in filenamesfind ~ -name "*.txt" -print0 | xargs -0 grep "TODO"
Find empty filesfind ~ -type f -empty
Find empty directoriesfind ~ -type d -empty
OR conditionfind ~ \( -name "*.jpg" -o -name "*.png" \)
NOT conditionfind ~ -not -name "*.pdf"

Conclusion: find as a File System Language

The find command is more than a search tool — it is a language for describing files by their properties and acting on what you find. Once you internalize its structure (starting point, tests, actions, operators), you can express virtually any file selection criterion and automate operations that would be tedious or impossible with graphical tools.

The key patterns to master are: searching by name with wildcards, filtering by type, combining criteria with implicit AND, using -exec to act on results, using -print0 with xargs for safe pipeline processing, and reaching for -not and parenthesized -o when you need to exclude or express alternatives.

find is one of those commands that rewards continued learning. Each new option you discover — -newer, -perm, -empty, -printf — adds a new capability to your toolkit. The command’s designers gave it extraordinary depth precisely because file management tasks are extraordinarily varied, and having one powerful, composable tool for all of them is more valuable than a dozen simpler tools with overlapping capabilities.

Master find, and the Linux filesystem becomes a queryable, programmable space rather than a static collection of paths.

Share:
Subscribe
Notify of
0 Comments
Inline Feedbacks
View all comments

Discover More

Rogo Raises $75M Series B for AI-Powered CFO Workflow Platform

Financial automation startup Rogo raises $75 million Series B funding to unify and automate finance…

Understanding the Difference Between System Software and Application Software

Understanding the Difference Between System Software and Application Software

Learn the key differences between system software and application software, how they interact, and why…

The Difference Between Hibernation, Sleep, and Shutdown

Understand the key differences between hibernation, sleep, and shutdown on your computer. Learn how each…

Navigating the iOS Interface: Essential Tips for Beginners

Discover essential tips for navigating the iOS interface. Learn how to manage apps, use Siri…

ServiceNow’s $7.75B Armis Deal Signals a New Era of AI-Driven Cyber Defense

ServiceNow’s Armis acquisition highlights how AI is reshaping enterprise security priorities: visibility, automation, and governance.

ATSC Showcases NextGen TV 3.0 at CES 2026 With New Home Solutions

ATSC will showcase NextGen TV 3.0 receivers and multiunit dwelling solutions at CES 2026, advancing…

Click For More
0
Would love your thoughts, please comment.x
()
x