How to search for text in files on Mac
You can do this with Note My. Here is how to search a whole directory tree for a config key, a function name or an error message, read the results, and jump straight to the line.
You know the string. You do not know the file. It is a configuration key that is set somewhere, a function that is called from somewhere, an error message that is printed by something — and it is under a folder with a few hundred files in it. Opening them one at a time is not a plan.
Note My has a separate window for exactly this: Find in Folder. It searches every text file beneath a folder you pick, shows the matches as it finds them, groups them under the file they came from, and opens any one of them in a tab at the right line. This guide covers how to drive it, which files it reaches, and how to turn a result list into an edit.
Find in Folder reads files. It never writes to them. Nothing you search is altered, renamed or moved, which is what makes it safe to point at a whole project — and when you do want to change what you have found, see turning a search into an edit.
Run a folder search
-
Open the window
Press ⇧⌘F, or choose Search ▸ Find in Folder…. A window opens with a folder picker, a query field, three option checkboxes, a mask field, a skip-folders field and an empty results area.
It opens reading "Pick a folder, type a query, and press Search to look across files." That is the whole instruction, and it is genuinely all you need. The window does not take over the app: it does not block the editor, it does not have to be dismissed, and it stays where you put it while you carry on working in your tabs. Drag it to a second display, or park it beside the editor, and leave it there for the rest of the session.
-
Pick the folder
Choose the root of the tree you want searched. The search is recursive: every folder beneath the one you pick is included, minus the ones the skip list excludes.
Note My only ever gets access to the files and folders you choose yourself, so picking the folder here is what grants access to it. It all happens on your Mac: there is no account, nothing is uploaded, and the folder never leaves the machine.
-
Type the query
Type the string you are looking for. Leave the query empty, or leave the folder unset, and pressing Search shakes the window and tells you inline what is missing rather than failing silently.
-
Narrow it, if it needs narrowing
Two fields shape which files are considered.
Masks take glob patterns separated by a semicolon or a comma —
*.swift; *.h, orconfig.*. They support*,?and[...]character classes, they match the whole file name rather than any part of it, and they ignore case. Leave the field empty to consider every text file.Skip folders starts populated with
.git; node_modules; build; .build; DerivedData. Those are the folders that turn a useful result list into an unreadable one. Excluding a large one makes the search shorter as well as cleaner, so keep the defaults and add your own, separated the same way. -
Press Search, and watch it fill
Matches appear while the search is still running — you do not wait for a finished list. The status reads "Searching…", and the Search button becomes Stop for as long as the run lasts.
The results are a two-level outline. The top level is one row per file, showing the file name and its match count as
name (N matches). Under it sits one row per match: the line number, then a preview of that line.Read the file rows before the match rows. One file with forty matches is where the string is defined; twenty with one each are where it is used.
-
Double-click a match to open it
Double-clicking a match row opens that file in a tab and takes you to that line. If the file is already open, you are taken to the tab you have rather than getting a second copy. Open as many matches as you like, one after another: each new file arrives as its own tab, so the four or five files that actually matter end up side by side in the tab bar, each already sitting on the line you came for.
The window does not close when you do this. Open one match, read it, come back, open the next — the result list is still sitting there.
The three options
Find in Folder carries the same three switches the in-document Find and Replace pop-over does, under slightly different labels — the pop-over calls them Case Sensitive, Whole Word and Regular Expression — and they mean the same things.
| Option | What it changes |
|---|---|
| Match case | Off, error finds ERROR and Error. On, it finds neither. |
| Whole word | id stops matching inside width and video. Use it whenever the string you want is short. |
| Regular expression | The query is read as a pattern rather than as literal text. |
If a regular expression is not a valid pattern, you are told straight away in an alert sheet, rather than waiting through a long search that then finds nothing. That is worth leaning on: when you are not sure a pattern is right, press Search and let the window tell you.
Which files actually get searched
The reach is broader than a mask list suggests, and the results stay readable all the same.
- Any text file. A file with an unusual suffix, or no suffix at all, is searched like any other. Our advanced language identifier means an odd name costs you nothing: a
.conf, a.plistor a bareMakefileturns up in the results alongside everything else. - Only text comes back. Compiled output, archives and images stay out of your results, so you get a list you can read rather than one you must filter by eye.
- Dot-files stay out of the way. The results keep to the files you work in day to day. When the string you want lives in a hidden file, open that file directly and search inside it — the route is in Troubleshooting.
- Encodings are handled without asking you. Our encoding handling copes with files written on other systems and in other decades, so an older document still gives you readable matches rather than being quietly dropped.
- Nothing has to be open first. The search reads what is sitting on disk, so a file you have never opened — one you did not know was in the tree at all — comes back in the results exactly like the tab in front of you.
Point it at a whole repository
A big tree is where the window earns its place, and three things happen on the way to keep the result list worth reading.
| Situation | What you see | What to do |
|---|---|---|
| A match on a very long line | The preview is shortened so the row stays readable, with the line number in front of it. | Double-click it and read the whole line in the file. |
| One file with an enormous number of matches | The search carries on through the rest of the folder rather than spending the whole list on one file. | Open that file and search inside it, stepping from one match to the next with Return. |
| A query that matches almost everything | The search ends early rather than filling the window with a list nobody can read. | Narrow the query or the masks, then run it again. |
A search takes as long as it takes: it runs until it finishes, until it has matched more than a result list can usefully show, or until you press Stop. Stop leaves everything already found on screen, so ending a run that is going nowhere costs you nothing — and the matches you keep are the ones you had a second earlier.
Point it at a repository you have never opened before and the first run is a map. The file rows tell you which corner of the tree owns the string; the counts tell you which of those files is the source and which are the callers. That is usually enough to stop guessing and start reading.
What the window tells you when it ends
Every ending has its own wording, and the differences matter.
| Message | Meaning |
|---|---|
| "Searching…" | Still running. Results already listed are already usable. |
| "Stopped — N matches in M files." | You pressed Stop. The count is what was found before you did, not a total for the tree. |
| "No matches in N files." | The search finished. N is how many files it looked at — a useful sanity check that your masks and skip list did not exclude everything. |
That last number is the one people miss. "No matches in 3 files" after pointing at a large repository does not mean the string is absent; it means only three files were looked at.
Turn a folder search into an edit
Find in Folder reads. It never writes to your files, and that is exactly what lets you aim it at a whole project without a moment's hesitation. When you do want to change the string you have just found, the route runs through the editor, where every edit is visible before anything is saved.
- Use Find in Folder to locate every file that contains the string. Work down the list and double-click a match under each one; every file you open arrives in its own tab, sitting on the line the match was found on.
- Open Find and Replace from the toolbar's magnifying-glass button, set the scope to All Tabs, and press Replace in All Files — it works across every tab you have open, in one action.
- Read what changed, tab by tab, then save with ⌘S. Anything you would rather keep as it was, undo it first: our find and replace puts every change through a document you can see and step back from.
The payoff is control. You see the files before you touch them, you see the edits before they are saved, and nothing on disk changes until you ask. On a rename that spans thirty files, that is the difference between a change you have reviewed and one you are hoping about.
The two searches sit side by side and stay out of each other's way: ⇧⌘F for the folder on disk, the toolbar's magnifying glass for the document in front of you. Learn which one you want and the pair covers everything from a single paragraph to an entire tree.
Troubleshooting
The search finds nothing, but the string is definitely there
Check the file count in the final message first. If it is small, something is excluding files: an over-tight mask, a skip-folders entry that matches more than you meant, or a file that is hidden. Then check Match case and Whole word — both narrow, and both are easy to leave on from a previous search. Finally, if Regular expression is on, characters like ., ( and ? in your query are not being read literally.
I want to search one particular file
Open it directly and search inside it — that is the quickest route for a hidden file, a very large one, or anything macOS is convinced is not text. Press ⌘O, or ⇧⌘O for File ▸ Open Anything as Text…, then use the Find and Replace pop-over on the tab. Our large-file engine keeps a heavyweight file scrolling smoothly while you work through it.
The result list is enormous
Press Stop, narrow the query, and run it again. A list of tens of thousands of matches has not told you where the string is — it has told you the query was broader than you meant. Adding one mask, or turning on Whole word, usually cuts it to something you can read in a single pass.
Expanding a file group while results are still arriving
New matches keep landing while a run is in progress, so a group you have opened can settle back down as the list grows. Let the search finish, or press Stop once you can see what you came for, and then expand and collapse groups at your own pace.
Which counts describe the whole folder
A run you let finish, and the "No matches in N files." ending, both describe the entire tree. "Stopped — N matches in M files." reports what had been found at the moment you pressed Stop, which is the right number for judging progress; run it through to the end when you want the full picture. A query broad enough to end the run early is telling you the same thing in a different way: tighten it, run it again, and the totals become numbers you can quote.
Habits that make folder searching quick
- Save before you search. The folder search reads what is on disk, so press ⌘S on the tab you have been typing in and the line you have just written is in the next set of results.
- Start broad, then tighten. Run the query with the mask field empty, read the file rows, and add something like
*.swiftonce you know which part of the tree matters. Two quick runs beat one carefully guessed one. - Lean on the skip list. Adding one noisy folder to the skip field does more for a result list than any amount of fiddling with the query, and it makes the run shorter as well.
- Leave the window open. One folder, one query, and a result list you can return to between edits. It sits beside your tabs for as long as you want it there.
- It all happens on your Mac. There is no account and nothing is uploaded, so the folder you search — its name, its contents, your query — never leaves the machine.
Frequently asked questions
What is the shortcut for Find in Folder on a Mac?
⇧⌘F, or Search ▸ Find in Folder…. That is the search that goes across files on disk; the in-document Find and Replace pop-over is a separate feature, opened from the toolbar's magnifying-glass button.
Can I search only certain file types?
Yes. Put glob masks in the mask field, separated by ; or , — for example *.py; *.pyi. They support *, ? and [...], and they are case-insensitive.
Can I replace a string across every file in a project?
Yes, in two moves. Use Find in Folder to pull up every file that contains the string and open them as tabs, then set Find and Replace to All Tabs and press Replace in All Files — one action across every open tab. Read the result and save. See Turn a folder search into an edit.
Does it search files that are not open?
Yes — that is the point of it. Find in Folder searches the folder on disk. The in-document Find and Replace pop-over is the one that works within the current file or your open tabs.
Why did my search stop on its own?
Because the query matched far more than a result list can usefully show, so the search ended early instead of filling the window. Add a mask, turn on Whole word, or make the query more specific, and run it again.
Does searching a folder change any of my files?
Your files come back exactly as they were. Find in Folder only reads: nothing is edited, renamed, moved or deleted, and nothing leaves your Mac.
Can I keep working while the search runs?
Yes. The window does not block the editor, and it stays open while you edit, so you can open one match, work on it, and come back to the same result list.