Bash Find

The find command searches folders for files by name, type, size, or age. It walks through every subfolder and reports each match. Use it when you know a file exists somewhere but cannot remember where.

How Find Works

  find  WHERE   WHAT   ACTION
         |       |       |
         |       |       +--> print, delete, run a command
         |       +----------> name, type, size, age
         +------------------> starting folder

Basic Syntax

find folder -option value

A dot means the current folder. Without an action, find prints each match.

Search by Name

find . -name "notes.txt"
find . -name "*.log"
find . -iname "report*"

The -name option respects letter case. The -iname option ignores it. Quotation marks stop Bash from expanding the wildcard before find sees it.

Search by Type

find . -type f      # files only
find . -type d      # folders only
find . -type l      # symbolic links

Search by Size

find . -size +10M     # larger than 10 megabytes
find . -size -1k      # smaller than 1 kilobyte
find . -size 5M       # exactly 5 megabytes
find . -empty         # empty files and folders

A plus sign means "more than". A minus sign means "less than".

Search by Time

find . -mtime -7      # changed in the last 7 days
find . -mtime +30     # changed more than 30 days ago
find . -mmin -60      # changed in the last 60 minutes
find . -atime +90     # not opened for 90 days

Search by Owner and Permission

find . -user asha
find . -perm 644
find . -perm -u+x     # files the owner can run

Combine Conditions

Conditions combine with -and (default), -or, and -not. Parentheses group them and need backslashes.

find . -type f -name "*.txt" -size +1M
find . \( -name "*.jpg" -o -name "*.png" \)
find . -type f -not -name "*.log"

Limit the Search Depth

find . -maxdepth 1 -type f
find . -mindepth 2 -name "*.sh"

The first command stays in the current folder. The second skips the top level.

Run an Action on Each Match

Delete Files

find . -name "*.tmp" -delete

Run the same command without -delete first. Review the list, and add the action only when the list looks right.

Run a Command With -exec

find . -name "*.txt" -exec wc -l {} \;
find . -name "*.sh" -exec chmod +x {} \;

The braces {} stand for each found file. The backslash and semicolon end the command.

Batch Many Files Into One Command

find . -name "*.log" -exec grep -l "error" {} +

The plus sign passes many files at once, which runs faster.

Handle Names With Spaces

find . -name "*.txt" -print0 | xargs -0 ls -l

The -print0 and -0 pair separates names with a null character, so spaces cause no trouble.

Practical Example: Clean Old Logs

#!/bin/bash
folder="/var/log/myapp"
find "$folder" -type f -name "*.log" -mtime +30 -print
read -p "Delete these files? (y/n) " answer
if [ "$answer" = "y" ]; then
  find "$folder" -type f -name "*.log" -mtime +30 -delete
  echo "Old logs removed"
fi

The script lists the files first and deletes them after confirmation.

Key Takeaways

  • find folder -name pattern searches by name.
  • -type, -size, and -mtime filter by kind, size, and age.
  • -exec command {} \; runs a command on every match.
  • -maxdepth limits how deep the search goes.
  • Preview matches before using -delete.