How to Find Files in Bash

How to Find Files in Bash

There was a period early in my Linux journey where I’d just browse directories manually trying to remember where I put a file, which is a hilariously slow way to work once you know the find command exists. Finding files by name, type, size, modification date, or even content is one of those skills that quietly saves hours over time, and it’s worth learning properly rather than just memorizing one or two commands you copy-paste forever.

In this guide, I’ll cover find, locate, and grep (for searching file contents), with practical examples for each, plus how to combine them into more powerful one-liners.

The find Command Basics

find searches a directory tree recursively based on criteria you specify.

find /path/to/search -name "filename.txt"

This searches starting at /path/to/search for any file named exactly filename.txt.

Searching by Name

Exact Match

find . -name "report.txt"

The . means “start searching from the current directory.”

Case-Insensitive Search

find . -iname "report.txt"
  • -iname — ignores case, so this would also match Report.TXT or REPORT.txt.

Using Wildcards

find . -name "*.log"

This finds every file ending in .log, regardless of what comes before it. Remember to quote the pattern so Bash doesn’t try to expand the wildcard itself before passing it to find.

Searching by File Type

find . -type f -name "*.conf"
  • -type f — restrict results to regular files only (not directories).
find . -type d -name "logs"
  • -type d — restrict results to directories only.

Other type options include -type l for symbolic links.

Searching by Size

find . -type f -size +100M
  • -size +100M — finds files larger than 100 megabytes.
find . -type f -size -1k
  • -size -1k — finds files smaller than 1 kilobyte.

Size units include c (bytes), k (kilobytes), M (megabytes), and G (gigabytes).

Searching by Modification Time

find . -type f -mtime -7
  • -mtime -7 — files modified within the last 7 days.
find . -type f -mtime +30
  • -mtime +30 — files modified more than 30 days ago.

For more precision down to minutes:

find . -type f -mmin -60
  • -mmin -60 — files modified within the last 60 minutes.

Searching by Permissions

find . -type f -perm 644

This finds files with exactly 644 permissions (read/write for owner, read-only for group and others).

find / -type f -perm -4000
  • -perm -4000 — finds files with the SUID bit set, which is often used in security audits to check for potentially risky executables.

Searching by Owner

find /home -user alice

Finds all files owned by the user alice.

find / -group developers

Finds all files owned by the group developers.

Combining Multiple Conditions

You can combine conditions using logical operators.

AND (Default Behavior)

find . -type f -name "*.log" -size +10M

Multiple conditions listed together are implicitly ANDed — this finds .log files larger than 10MB.

OR

find . -name "*.log" -o -name "*.txt"
  • -o — matches files with either extension.

NOT

find . -type f -not -name "*.txt"

Finds all files except .txt files.

Executing Commands on Found Files

This is where find becomes genuinely powerful — you can run a command against every result.

find . -name "*.tmp" -exec rm {} \;

Breaking this down:

  • -exec — run the specified command on each matched file.
  • {} — placeholder replaced with the current file path.
  • \; — marks the end of the command (escaped so Bash doesn’t interpret the semicolon itself).

For better performance on large result sets, use + instead of \;, which batches multiple files into fewer command invocations:

find . -name "*.tmp" -exec rm {} +

A Safer Alternative: -exec With Confirmation

find . -name "*.tmp" -ok rm {} \;
  • -ok — works like -exec but prompts for confirmation before running the command on each file, which is a good habit when deleting things in bulk.

Searching by File Content With grep

While find locates files based on metadata (name, size, date), grep searches inside file contents.

grep -r "TODO" /path/to/project
  • -r — recursive search through all files and subdirectories.

Case-Insensitive Content Search

grep -ri "error" /var/log/

Showing Line Numbers

grep -rn "function loadData" src/
  • -n — shows the line number where each match occurs, extremely useful when tracking down code.

Combining find and grep

find . -name "*.py" -exec grep -l "import requests" {} \;

This finds every Python file that imports the requests module. -l tells grep to print only the filenames of matches, not the matching lines themselves.

Using locate for Faster Searches

find searches the filesystem in real time, which can be slow on large systems. locate instead searches a prebuilt index, making it much faster.

locate report.txt

Before using it, make sure the index is updated:

sudo updatedb

The tradeoff is that locate won’t reflect very recent file changes until the index is refreshed, whereas find always reflects the current state of the filesystem.

Real-World Use Cases

Cleaning up temporary files:

find /tmp -type f -mtime +7 -exec rm {} \;

Removes temporary files older than 7 days, a common maintenance task on servers.

Finding large files eating disk space:

find / -type f -size +500M 2>/dev/null

The 2>/dev/null suppresses “permission denied” errors from directories you can’t access, keeping output clean.

Auditing world-writable files (a security check):

find / -type f -perm -0002 2>/dev/null

This finds files writable by anyone, which is often a red flag worth investigating.

Finding recently modified configuration files after a suspected breach:

find /etc -type f -mtime -1

Automation Example: Cleanup Script

#!/bin/bash

TARGET_DIR="/var/log/myapp"
DAYS_OLD=14

echo "Searching for log files older than $DAYS_OLD days in $TARGET_DIR..."

find "$TARGET_DIR" -type f -name "*.log" -mtime +$DAYS_OLD -print -exec rm {} \;

echo "Cleanup complete."

How it works internally:

  1. find searches $TARGET_DIR for .log files older than $DAYS_OLD days.
  2. -print shows each matched file before deleting it, so you get a log of what was removed.
  3. -exec rm {} \; deletes each matched file individually.
  4. This script could be scheduled with cron to run weekly, automatically keeping log directories from growing indefinitely.

Best Practices

  • Always test find commands with -print (or no -exec at all) before adding a destructive action like rm.
  • Use -iname when you’re not sure about the exact case of a filename.
  • Prefer + over \; with -exec for better performance on large result sets.
  • Redirect stderr to /dev/null when searching system-wide to avoid clutter from permission errors, but don’t do this while debugging — you might miss meaningful errors.
  • Combine find with xargs for even more flexible command execution: find . -name "*.log" | xargs rm.

Security Considerations

  • Be extremely cautious with -exec rm — always dry-run with -print first to confirm exactly which files will be affected.
  • When searching system directories for security audits (like SUID files or world-writable files), be aware that some results are legitimate and expected — don’t blindly remove permissions without understanding why they were set.
  • Avoid running find with -exec as root against untrusted directories, since crafted filenames could potentially be used to inject unexpected behavior into poorly quoted commands.

Optimization Tips

  • Use locate instead of find for simple filename searches on systems where the index is kept up to date — it’s dramatically faster for large filesystems.
  • Limit find‘s search depth with -maxdepth when you know results are within a certain number of directory levels, which speeds up searches significantly on large trees:
find . -maxdepth 2 -name "*.conf"
  • Narrow searches to specific directories rather than searching from / whenever possible.

Troubleshooting Common Issues

“Permission denied” errors cluttering output: Redirect stderr with 2>/dev/null, but remember this hides real errors too, so use cautiously.

find seems to return nothing when you expect matches: Double-check your pattern is quoted ("*.log" not *.log), since an unquoted wildcard gets expanded by Bash itself before find ever sees it.

locate returns outdated results: Run sudo updatedb to refresh the index.

-exec command fails on filenames with spaces: Use {} combined with proper quoting or switch to -exec ... + instead of \;, which handles this more gracefully in most cases.

Frequently Asked Questions

What’s the difference between find and locate? find searches the filesystem live and reflects current state but can be slower. locate searches a prebuilt index, which is fast but may be slightly out of date.

Can find search file contents directly? Not on its own — combine it with grep using -exec for content-based searches.

Is find case-sensitive by default? Yes, use -iname instead of -name for case-insensitive matching.

How do I find files modified between two specific dates? Use -newer with a reference file, or combine -mtime conditions, or use find with -newermt for specific date strings (GNU find extension): find . -newermt "2026-01-01" ! -newermt "2026-02-01".

Common Mistakes to Avoid

  • Forgetting to quote wildcard patterns, causing unexpected shell expansion before find runs.
  • Running -exec rm without testing the search criteria first.
  • Searching from / without narrowing scope, resulting in extremely slow searches and pages of permission errors.
  • Confusing -name (filename pattern) with -iname (case-insensitive) and getting unexpected empty results.

Summary

Finding files efficiently in Bash comes down to mastering find for metadata-based searches (name, size, type, date, permissions) and grep for content-based searches, with locate as a fast alternative for simple filename lookups. Once you’re comfortable combining conditions and using -exec safely, you can automate cleanup tasks, security audits, and everyday file management directly from the terminal.

References

Total
1
Shares

Leave a Reply

Previous Post
How to Copy Files and Directories in Bash

How to Copy Files and Directories in Bash

Next Post
How to Sort Files in Bash

How to Sort Files in Bash

Related Posts