How to find and replace across many Markdown files on a Mac

Checked November 2026 against the macOS sed manual, the VS Code documentation and BBEdit's feature list. Coffee isn't affiliated with Microsoft or Bare Bones Software.

Because Markdown notes are ordinary files, any tool that edits files can change a word in all of them. In Terminal, sed -i '' does it in one line, with no preview. VS Code and BBEdit search a whole folder and show you the matches first. In Coffee, Note > Replace in All Notes… (⌥⇧⌘F) lists every match with what it becomes, lets you leave any out, and keeps each note's old version before it changes anything.

Whichever you use, take a copy first. A replace across a hundred files is quick to do and slow to undo by hand.

Before you start

Three habits save most of the trouble:

  • Make a copy you can go back to. If your notes are in Git, commit first, so git diff shows exactly what changed and git restore . takes it all back. If they aren't, duplicate the folder in Finder, or check that Time Machine has a recent backup.
  • Search before you replace. Look at what matches before you change it. A name like "Ann" also matches "Annual" and "Planning".
  • Close the files in other editors. An app holding a note open may save its own copy over yours afterwards.

In Terminal, with sed

First, see which files contain the word. Run this from your notes folder:

grep -rl --include='*.md' 'Acme' .

Then replace it. macOS comes with the BSD version of sed, and its -i option needs an extension for a backup file. An empty one, written '', means no backup:

sed -i '' 's/Acme/Apex/g' *.md

This is the line most often copied wrong, because instructions written for Linux use sed -i with nothing after it. On a Mac, sed then takes your pattern as the backup extension and stops with an error such as "invalid command code".

To keep a backup of every file, give an extension instead, then delete the backups once you're happy:

sed -i '.bak' 's/Acme/Apex/g' *.md
find . -name '*.md.bak' -delete

The macOS manual itself advises against a zero-length extension when editing in place, as you risk corruption or partial content if the disk runs out of space. With Git or a copy of the folder, that risk is smaller, but it's the reason the backup option exists.

*.md only covers the current folder. For every folder inside it too, including names with spaces:

find . -name '*.md' -print0 | xargs -0 sed -i '' 's/Acme/Apex/g'

To match a whole word only, so that "Acme" changes and "AcmeCorp" doesn't, macOS sed uses [[:<:]] and [[:>:]] for the start and end of a word:

sed -i '' 's/[[:<:]]Acme[[:>:]]/Apex/g' *.md

In Terminal, with perl

If you already know regular expressions from other languages, perl comes with macOS and behaves the same as it does elsewhere, so \b means a word boundary and -i.bak keeps a backup:

perl -pi.bak -e 's/\bAcme\b/Apex/g' *.md

Both tools change every match with no questions. They're the right choice when the change is simple and you can check it afterwards with git diff. They're the wrong choice when some matches should stay as they are.

In VS Code

VS Code is free and does this well. Open your notes folder with File > Open Folder, then press ⇧⌘F for search across files. Expand the search box to show the Replace field.

From its documentation:

  • There are fields for files to include and exclude, taking patterns such as **/*.md, separated by commas.
  • There's a Match Case toggle, and you can search with a regular expression.
  • Typing a replacement shows a diff of the pending changes before anything is applied.
  • You can replace across all files, replace all in one file, or replace a single change.

A toggle called Use Exclude Settings and Ignore Files decides whether .gitignore and your exclude settings apply, so check it if a note you expected isn't in the results.

In BBEdit

BBEdit is a long-standing Mac text editor. Its feature list describes multi-file search across folders, individual files, open documents, projects and previous search results, with grep pattern search and replace based on PCRE, and advanced file filtering. Results open in a browser where you can view and open each match.

It suits large folders and complicated patterns. Check Bare Bones' site for its current pricing.

In Coffee

Coffee has this built in, for the notes in your library. Choose Note > Replace in All Notes…, or press ⌥⇧⌘F.

Type what to find and what to replace it with. There are three options: Match case, Whole words and Regular expression. With a regular expression, $1 and $& work in the replacement, and otherwise the replacement is taken exactly as you typed it. A pattern Coffee can't read is shown as a problem rather than run.

Each note with matches is listed with its folder and a count. Under it, each match appears on its own line, with its line number, the old text struck through and the new text beside it. Every match has a checkbox, and so does each note, so you can leave out one match or a whole note. Nothing is written until you press Replace, and Coffee asks once more first, saying how many matches in how many notes.

What happens to your files:

  • Each note keeps a version first. Before a note changes, its current text goes into its version history, whatever else was kept recently.
  • The whole replace can be undone. After replacing, an Undo replace button puts back every note it changed, as long as the note hasn't changed again since. Any that have are left alone and named, and their history still has the earlier text.
  • Open notes change in their window. If a note is open, it's changed in its editor, as one step that ⌘Z can undo, and unsaved typing is searched too.
  • Notes that changed since the search are skipped. If something edits a note between your search and your Replace, Coffee leaves it alone and tells you which.
  • Private notes are never searched or changed here.

Its limits are worth knowing. It covers every note in your library, not one folder, so use Whole words or a regular expression to narrow what matches. It stops listing at about 2,000 matches, so for a bigger change, replace those and search again. And it only reaches notes in your Coffee library, not other folders on your Mac. For those, the Terminal or VS Code is the way.

Coffee is Mac only, with macOS 15 or later. It's free for 14 days without a card, then €3 a month, €29 a year, or €79 once with two years of updates.

Which one to use

  • A simple change you'll check with Git afterwards: sed -i '' or perl -pi.
  • A change where some matches should stay, in any folder: VS Code or BBEdit.
  • Your notes, in Coffee, with a way back: Replace in All Notes.

If the word is also a link target, such as a note's title in [[double brackets]], a plain replace changes the text and not the file name. Renaming the note itself is better for that, and there's a guide to keeping wiki links working.

Questions

Why does sed -i fail on my Mac?

macOS uses the BSD version of sed, where -i needs a backup extension. Write sed -i '' 's/old/new/g' file.md for no backup, or sed -i '.bak' to keep one.

How do I replace only whole words in Terminal?

With macOS sed, wrap the word in [[:<:]] and [[:>:]]. With perl, use \b on each side, as in perl -pi -e 's/\bold\b/new/g' *.md.

Can I preview a replace before it happens?

Yes, in VS Code, BBEdit and Coffee. VS Code shows a diff of the pending changes, and Coffee lists each match with its new text and a checkbox. sed and perl change files without a preview, so run grep first and git diff afterwards.

Can I undo a replace across all my notes?

With Git, git restore . puts back everything since your last commit. In Coffee, Undo replace puts back every note that hasn't changed since, and each note's version history keeps its text from before the replace.

Does Coffee's Replace in All Notes change private notes?

No. Private notes are never searched or changed by it.