Terminal

How to Find a File on Mac Terminal by Name (find, mdfind)

Published Nov 9, 2026
Tested on a real Mac. Ran /usr/bin/find (-name, -iname, -path, -type, -maxdepth, -size, -mtime, -empty, -exec, -o), grep -r, mdfind (-name, -onlyin, -count, kMDItemFSName queries), mdls, mdutil -s and locate on an M3 Mac (macOS 26.6.2, zsh 5.9) in a scratch folder; the sudo launchctl command that builds the locate database and open -R (which opens Finder) were not executed. Test machine: MacBook Air (M3, 16 GB), macOS Tahoe 26.6.2, zsh 5.9.
On this page
  1. Find a file by name (recursive)
  2. Find files by extension or partial name (wildcards)
  3. Case-insensitive search
  4. Find a file inside a specific folder (-path) and limit depth
  5. Filter by size, date, or empty files
  6. Hide “Permission denied” and “Operation not permitted”
  7. Search the whole Mac instantly with mdfind (Spotlight)
  8. What about locate?
  9. Common questions

To find a file by name in Mac Terminal, use find with the folder to search and -name:

find . -name "app.js"

The . means “start here”, and find searches every subfolder below it. Always put the name in quotes. To search your whole Mac in a split second, use Spotlight’s command-line tool instead: mdfind -name "report".

I tested every command below on a MacBook Air M3 (macOS Tahoe 26.6.2, zsh 5.9) in a scratch folder with this layout:

./My Notes/Meeting Notes.txt
./project/README.md
./project/docs/Report.PDF
./project/docs/report-final.pdf
./project/docs/big.bin
./project/src/app.js
./project/src/utils/helpers.js

Along the way I hit two traps most guides skip: zsh breaking unquoted wildcards, and mdfind -name ignoring .app names.

Find a file by name (recursive)

find is built into macOS at /usr/bin/find. It is recursive by default, so you don’t need a -r flag.

find . -name "app.js"
./project/src/app.js

Search a different folder by giving its path first. A file name with spaces just needs quotes:

find ~/Documents -name "Meeting Notes.txt"

In my test folder, find . -name "Meeting Notes.txt" printed ./My Notes/Meeting Notes.txt.

If find prints nothing, there was no match. It does not say “not found”. If the folder itself is wrong, you get an error and exit code 1:

find: nothere: No such file or directory

Find files by extension or partial name (wildcards)

Use * to match any characters. This finds every JavaScript file in all subfolders:

find . -name "*.js"
./project/src/utils/helpers.js
./project/src/app.js

Partial names work the same way. *Notes* matches anything with “Notes” in it, folders included:

find . -name "*Notes*"
./My Notes
./My Notes/Meeting Notes.txt

Add -type f for files only, or -type d for folders only. find . -type f -name "*Notes*" returned just the .txt file.

To match several extensions at once, group them with -o (or):

find . \( -name "*.md" -o -name "*.pdf" \)
./project/docs/report-final.pdf
./project/README.md

The zsh wildcard trap

This is the mistake I see most. Without quotes, zsh tries to expand *.js itself before find ever runs. If the current folder has no .js file, zsh stops with an error:

zsh: no matches found: *.js

That’s annoying, but at least it’s loud. The worse case is when the current folder does contain a match. I ran the unquoted version inside project/src, which has app.js in it:

find . -name *.js
./app.js

zsh replaced *.js with app.js, so find only searched for that exact name and silently missed utils/helpers.js. Bash behaves differently here, which is why old tutorials get away without quotes. In zsh (the default Mac shell since Catalina), always quote the pattern.

-name is case-sensitive, even though the Mac file system is not. My folder had both Report.PDF and report-final.pdf:

find . -name "report*.pdf"
./project/docs/report-final.pdf

Use -iname to ignore case:

find . -iname "report*.pdf"
./project/docs/report-final.pdf
./project/docs/Report.PDF

Find a file inside a specific folder (-path) and limit depth

-name only looks at the last part of the path. If you include a slash, it never matches, and find quietly prints nothing with exit code 0:

find . -name "src/app.js"

Use -path when you care about the folder too:

find . -path "*src/*.js"
./project/src/utils/helpers.js
./project/src/app.js

To stop find from going too deep, use -maxdepth. find . -maxdepth 2 -name "*.md" found ./project/README.md without descending further. This is the easy way to keep a search of your home folder fast.

Filter by size, date, or empty files

find can match more than names. These all worked on the test folder:

find . -size +1M                 # bigger than 1 MB
find . -type f -mtime -1         # changed in the last 24 hours
find . -type f -mtime +30        # not changed in 30+ days
find . -type f -mmin -60         # changed in the last hour
find . -type f -empty            # zero-byte files

Add -exec ls -lh {} \; to see details for each match:

find . -size +1M -exec ls -lh {} \;
-rw-------@ 1 you  staff   5.0M Nov  9 10:04 ./project/docs/big.bin

For a full walkthrough of hunting down space hogs, see how to find large files on Mac.

To find files by what’s inside them rather than their name, use grep:

grep -rl "TODO" .
project/src/app.js

Hide “Permission denied” and “Operation not permitted”

Searching outside your own folders fills the screen with errors. Here is a search of a system folder:

find /private/var/db -maxdepth 2 -name "zzz"
find: /private/var/db/appinstalld: Operation not permitted
find: /private/var/db/diskimagesiod: Permission denied
find: /private/var/db/ExtensibleSSO/Configuration: Operation not permitted

That one search printed 48 error lines. “Permission denied” is classic Unix file permissions. “Operation not permitted” is macOS privacy protection, which blocks Terminal even when the file permissions would allow it. Send the errors to /dev/null:

find /private/var/db -maxdepth 2 -name "zzz" 2>/dev/null

One catch for scripts: the errors are hidden, but find still exits with code 1. Don’t use if find ... to test for a match. Check whether the output is empty instead.

Also, a deep scan of ~/Library stalled for over two minutes on my Mac before I stopped it. Use -maxdepth, or a more specific starting folder, or mdfind below.

Search the whole Mac instantly with mdfind (Spotlight)

find walks the disk folder by folder. mdfind asks the Spotlight index, so it is near-instant:

mdfind -name "Safari"

That returned 185 results in 0.05 seconds, including /Applications/Safari.app. Limit it to one folder with -onlyin, or just count matches with -count:

mdfind -onlyin /Applications -name "Safari"
mdfind -count -name "README"

If you see lines like [UserQueryParser] Loading keywords and predicates for locale, that’s harmless log noise on stderr. Add 2>/dev/null to hide it.

Why mdfind -name misses “Safari.app”

This one surprised me:

mdfind -name "Safari.app" | wc -l
       0

-name matches the Spotlight display name, not the real file name. mdls shows the difference:

mdls -name kMDItemDisplayName -name kMDItemFSName /Applications/Safari.app
kMDItemDisplayName = "Safari"
kMDItemFSName      = "Safari.app"

The display name hides the .app extension. It is also translated when your Mac uses another language: on my test Mac, Calculator’s display name is localized, so mdfind -name "Calculator" didn’t return Calculator.app at all. To match the exact file name, query kMDItemFSName:

mdfind "kMDItemFSName == 'Calculator.app'"
/System/Applications/Calculator.app

Add c after the quotes for case-insensitive wildcards: mdfind 'kMDItemFSName == "safari*.app"c'.

mdfind can’t see unindexed folders

Spotlight doesn’t index temp folders. mdfind -onlyin on my scratch folder in $TMPDIR returned nothing, even though the files were there, and mdutil -s reported Error: unknown indexing state for it. The same applies to folders you excluded in Spotlight settings. If mdfind comes up empty, fall back to find.

What about locate?

locate exists on macOS, but its database isn’t built by default:

WARNING: The locate database (/var/db/locate.database) does not exist.
To create the database, run the following command:

  sudo launchctl load -w /System/Library/LaunchDaemons/com.apple.locate.plist

I didn’t run that sudo command. Even once enabled, the database updates only weekly, so it misses new files. mdfind is the better fast option on a Mac.

ToolSpeedFinds new filesBest for
findSlower (walks disk)Yes, alwaysExact control, scripts, any folder
mdfindInstantYes, if indexedSearching the whole Mac
locateInstantNo (weekly update)Rarely worth enabling

Common questions

How do I find a file and open its folder in Finder?

Copy the path find prints, then run open -R on it to reveal it in Finder, for example open -R ./project/src/app.js. More options are in how to open a folder in Finder from Terminal.

How do I get the full path instead of ./?

Start the search from an absolute path: find "$PWD" -name "app.js" prints the full path, starting with /.

How do I search only the current folder, not subfolders?

Use find . -maxdepth 1 -name "*.txt", or simply ls *.txt.

Why does find in zsh say “no matches found”?

The pattern isn’t quoted, so zsh tried to expand it first. Use find . -name "*.txt" with quotes.

Can I delete the files find returns?

Yes, with -delete, but run the same command without it first and read the list. -delete has no undo and skips the Trash. If you’re making test files to practice on, see how to create a file in Terminal.