Linux & Shell guide · Last updated

How to Find a File in Linux (find Command Guide)

To find a file by name in Linux, run find /path -name "filename", for example find ~ -name "config.yaml". The find command walks a directory tree and tests every file against the conditions you give it: name, type, size, modification time, owner or permissions. It can then print, list, run a command on, or delete what it finds. This guide covers the searches you will use most (by name, directory, large files, recent changes), the safe way to use -exec and -delete, and when the faster locate, the friendlier fd or grep -r for searching file contents is the better tool. Everything here also works on macOS unless noted.

find syntax in one minute

The general form is find [where] [tests] [action]. The starting point defaults to the current directory; use . for here, ~ for your home directory or / for the whole system. Tests such as -name or -size filter the results, and the default action is -print, which lists matching paths. Multiple tests are combined with an implicit AND.

Searching from / as a normal user produces a flood of "Permission denied" lines from system directories. Redirect errors to /dev/null to hide them, or use sudo if you really need to search everywhere.

bash
find . -name "README.md"
find / -name "nginx.conf" 2>/dev/null
sudo find / -name "nginx.conf"

Find a file by name: -name and -iname

-name matches the file name (not the full path) against a shell-style pattern and is case-sensitive. -iname is the case-insensitive version, usually what you want when you are not sure of the capitalisation. Wildcards work: * matches anything, ? one character and [abc] one of a set. Always quote the pattern. Without quotes, the shell expands *.log against the current directory before find runs, which gives wrong results or an error such as "paths must precede expression".

To match against the whole path instead of the name, use -path or -ipath. To search for several names at once, group alternatives with -o (OR) inside escaped parentheses.

bash
find ~/projects -name "*.log"              # all .log files
find . -iname "readme*"                    # README.md, Readme.txt, readme
find . -name "*.ts" -not -name "*.test.ts" # exclude a pattern (! also works)
find . -path "*/src/components/*.tsx"      # match on the full path
find . \( -name "*.jpg" -o -name "*.png" \)   # either extension

Find directories and limit depth

-type restricts results to a kind of file: f for regular files, d for directories and l for symbolic links. Combine it with -name to find a directory by name. -maxdepth N stops find from descending more than N levels and makes searches in large trees much faster; put it right after the starting path, because GNU find warns if it appears after other tests. -empty finds empty files and directories.

To skip a heavy directory such as node_modules or .git entirely, use -prune. The pattern reads: if the path matches, prune it; otherwise (-o) apply the real test and print.

bash
find . -type d -name "node_modules"
find . -maxdepth 2 -type d -name "node_modules"
find /var/www -type l                      # symlinks
find . -type d -empty                      # empty directories

# Search for .js files but skip node_modules and .git
find . \( -name node_modules -o -name .git \) -prune -o -type f -name "*.js" -print

Find large files

-size filters by size. A + means larger than, - smaller than, and the suffix sets the unit: k for kibibytes, M for mebibytes and G for gibibytes. Note that without a suffix the unit is 512-byte blocks, and that sizes are rounded up to the unit, so -size -1M only matches empty files; use -size -1024k instead. Add -xdev when searching from / so find does not wander into other mounted file systems, network shares or /proc.

When the question is really "what is using my disk?", du is often more useful because it totals directory sizes. Sorting its human-readable output with sort -rh puts the biggest offenders first. For an interactive view, ncdu is worth installing.

bash
find / -xdev -type f -size +100M 2>/dev/null
find ~ -type f -size +1G -exec ls -lh {} +       # with human-readable sizes
find . -type f -size +10M -size -100M           # between 10 MB and 100 MB

# Largest files and folders under /var
sudo du -ah /var 2>/dev/null | sort -rh | head -20
du -sh -- * | sort -h                            # sizes of items in the current folder

Find files by modification time

-mtime N tests the last modification time in 24-hour periods: -mtime -7 means modified less than 7 days ago, -mtime +30 more than 30 days ago (strictly, at least 31 full 24-hour periods, because find discards the fractional part), and -mtime 0 within the last 24 hours. -mmin does the same in minutes. -atime and -ctime test access and status-change time. To compare against an exact date or another file, use -newermt or -newer.

bash
find . -type f -mtime -1                   # changed in the last 24 hours
find /var/log -type f -mtime +30           # older than ~30 days
find . -type f -mmin -15                   # changed in the last 15 minutes
find . -type f -newermt "2026-11-01"       # changed since a date
find . -type f -newer package.json         # newer than another file

Run commands on results: -exec, xargs and -delete

-exec command {} \; runs the command once per file, with {} replaced by the path. Ending with + instead of \; passes many paths to one command invocation, which is much faster for large result sets. -ok works like -exec but asks for confirmation before each file. When piping to xargs, use -print0 with xargs -0 so file names containing spaces or newlines are handled correctly.

-delete removes every match. It is the most dangerous flag in find for two reasons. First, there is no confirmation and no trash. Second, find evaluates the expression left to right, so find . -delete -name "*.tmp" deletes everything under the current directory before the name test is ever applied. Always run the exact command with -print (or nothing) first, check the list, then replace -print with -delete at the very end.

bash
find . -name "*.sh" -exec chmod +x {} \;        # once per file
find . -name "*.log" -exec gzip {} +            # batched
find . -name "*.bak" -ok rm {} \;               # ask before each delete
find . -name "*.txt" -print0 | xargs -0 grep -l "TODO"

# Safe delete workflow
find /tmp/build -type f -name "*.tmp" -mtime +7 -print     # 1. review
find /tmp/build -type f -name "*.tmp" -mtime +7 -delete    # 2. delete

Warning

Put -delete last, after every test, and never run it from / or your home directory without reviewing the -print output first. A misplaced -delete or a missing -name removes the whole tree.

locate: instant search from an index

locate searches a prebuilt database of file paths instead of walking the disk, so results come back in milliseconds even on a large system. The trade-off is freshness: the database is usually updated once a day by a scheduled job, so files created since then are missing until you run sudo updatedb. On Debian and Ubuntu install the plocate package (older systems use mlocate). On macOS, Spotlight's mdfind -name gives a similar indexed search.

bash
sudo apt install plocate
sudo updatedb
locate nginx.conf
locate -i "*.pem"          # case-insensitive
mdfind -name "invoice.pdf" # macOS Spotlight

fd: a faster, friendlier find

fd is a modern alternative written in Rust. It uses regular expressions by default, ignores hidden files and anything in .gitignore, colours its output and runs searches in parallel, which makes it the most pleasant option inside code repositories. On Debian and Ubuntu the package is fd-find and the binary is called fdfind; on macOS use brew install fd. Use -H to include hidden files and -I to stop respecting ignore files.

bash
fd config                 # names containing "config"
fd -e py                  # by extension
fd -t d node_modules -HI  # directories, including hidden and ignored
fd -e log -x gzip         # run a command on each result

Find files containing text: grep -r

find matches names and metadata, not file contents. To find which files contain a word or string, use grep -r. -n adds line numbers, -i ignores case, -l lists only the file names and --include limits the search to a pattern. ripgrep (rg) does the same faster and, like fd, skips ignored files automatically. To test a complex pattern first, try it in our regex tester.

bash
grep -rn "DATABASE_URL" .
grep -rli "todo" src/
grep -rn --include="*.py" "import requests" .
grep -rn --exclude-dir=node_modules "useEffect" .
rg "DATABASE_URL"

Find files in Linux: FAQ

Quick answers to common questions

How do I find a file by name in Linux?

Run find /path -name "filename", for example find ~ -name "notes.txt". Use -iname for a case-insensitive match and wildcards like "*.log" in quotes to match patterns.

How do I find large files in Linux?

Run find / -xdev -type f -size +100M 2>/dev/null to list files over 100 MB. For directory totals, du -ah /path | sort -rh | head -20 shows the largest files and folders first.

What is the difference between find and locate?

find searches the file system live, so results are always current but slower. locate searches a database updated periodically, so it is instant but misses files created since the last updatedb.

How do I search for text inside files in Linux?

Use grep -rn "text" /path to search recursively and show line numbers, or rg "text" with ripgrep for a faster search that respects .gitignore.

How do I find and delete files safely?

Run your find command with -print first and review the list. Then run the identical command with -delete as the last argument. Never place -delete before your tests.

Related tools and references

More developer guides