#

Editors

Subscribe
Editors October 29, 2026·7 min read

How to Find and Replace Text in Vim

For changes in one Vim buffer, use :s with the narrowest line range that covers the text you mean to change. Add g to change every match on those lines and c to approve each match yourself.

The basic Vim find-and-replace command

Vim substitution syntax

In Normal mode, :s/old/new/ replaces the first old on the current line. Press Esc to reach Normal mode, type the command, then press Enter.

Here is the complete form:

:[range]s/pattern/replacement/[flags]

The optional range names the lines. The pattern says what to find, the replacement says what to put there, and the flags control how Vim handles each match.

With the cursor on red red, entering :s/red/blue/ changes the line to:

blue red

Use /red to find text and :s to change it.

Replace in a range

Vim replacement ranges

The range sets which lines Vim examines. The g flag replaces every match on each of those lines. When replacing only part of a file, count the changed lines in the intended range and inspect a line outside that range to confirm it stayed untouched.

TaskCommand
Every match on the current line:s/old/new/g
Every match on lines 5 through 10:5,10s/old/new/g
Every match from the cursor line to the end:.,$s/old/new/g
First match on each line in the buffer:%s/old/new/
Every match in the buffer:%s/old/new/g

Here, . is the current line, $ is the last line, and % is every line in the current buffer. The percent sign does not reach other open buffers or files on disk.

Take a two-line buffer:

old old
old old

With :%s/old/new/, each line loses only its first old:

new old
new old
Vim global substitutions

With :%s/old/new/g, the same input becomes:

new new
new new

These examples assume the gdefault option is off. When it is on, the g flag reverses its per-line behavior.

Replace text in a Visual selection without changing nearby text

Vim visual selection

A Visual selection passed to :substitute becomes a range of lines, even when you select only a few characters.

Press v to select characters or V for whole lines. Typing : from Visual mode inserts the selection marks into the command line:

:'<,'>s/old/new/g

That command searches the selected lines, including text outside the selected substring. An r/neovim user wrote: “I know %s/thingToReplace/replacement/g to do replacements but it's global and impacts the whole file.”

Say one line contains:

cat cat cat

If you select only the middle cat, the marked-line substitution still changes the other two. The \%V atom tests whether a position is inside the Visual area:

:'<,'>s/\%Vcat/dog/g

The leading \%V tests only where the match starts. If the selection contains just the first character of cat, the pattern still matches and replaces the whole word. For this three-character example, add a second test to require the last character to be selected too:

:'<,'>s/\%Vca\%Vt/dog/g

Use the plain marked range for whole selected lines. For character-precise edits, put Visual-position tests at the match boundaries. Longer or multiline patterns need their own boundary placement. The \%V atom is Vim-specific.

Match exact text

Vim exact matching

Match complete words

To change the word cat and leave catalog alone, use the word-boundary atoms:

:%s/\<cat\>/dog/g

For the input cat catalog cat, the result is dog catalog dog. The iskeyword option defines what counts as a word character.

Match punctuation literally

In a Vim pattern, an unescaped dot matches any character. Use \. for a literal period, or \V to make most pattern punctuation literal:

:%s/\Vconfig.prod/new-name/g

The dot in config.prod is then plain text. \V mode affects only the search pattern, and the replacement rules and delimiter syntax stay the same.

Vim literal patterns

Choose a delimiter for paths

A slash-delimited substitute gets awkward when the replacement contains a Unix path. Use another allowed separator such as # and you don't have to escape the path slashes:

:%s#usrbin#/usr/bin#g

This replaces usrbin with /usr/bin/.

Control case and replacement text

Add i to force case-insensitive matching, or I to force case-sensitive matching:

:%s/cat/dog/gi
:%s/cat/dog/gI

The first command matches capitalization variants and writes the replacement exactly as typed. In the replacement, an unescaped & inserts the matched text.

Count or confirm replacements before accepting them

Vim confirmation choices

The n flag performs a count-only substitution:

:%s/old/new/gn

Vim reports how many matches fall in the command's range and changes nothing.

For per-match approval, use c:

:%s/old/new/gc
KeyMeaning
yReplace this match
nSkip this match
aAccept this and all remaining matches
qQuit the confirmation sequence
lReplace this match and stop

Suppose a line contains port port and only the first occurrence should become socket. With :%s/port/socket/gc, press y at the first prompt and n at the second. The resulting line is:

socket port

Press q to stop the prompts. Replacements you already accepted stay in the buffer.

Replace individual matches with cgn and the dot command

Vim cgn replacement

For a handful of scattered changes, cgn saves you from typing a full substitution. An r/vim user wrote: “Right now, I’m using :%s/old/new/gc to do this, but this feels very clunky to write out.” Search for /old and press Enter. Type cgn, enter the new text, and press Esc. Press n to jump to the next match and . to repeat the change. Use a range substitution when many matches get the same change.

Check, undo, save

Vim undo save

The result appears in the buffer before anything is written to disk.

  • Inspect: Compare the edited text with what you intended, including nearby text that should not change.
  • Undo or redo: In Normal mode, u reverses a change and Ctrl-r redoes it. Undo grouping decides how much one u reverses.
  • Write: Use :w once the buffer holds the version you want to save.
Vim changed text

Undo history helps during editing, but after a restart or an external overwrite only the undo information and backups that remain can restore your text. For a WordPress server configuration edit, keep a separate backup or a version-controlled diff so you can restore a saved configuration.

Fix errors

Vim substitution errors
SymptomCauseWhat to check
No match foundWrong range, case, or patternWhether the text is inside the range and the case matches
Too few or too many changesRange or g behaviorLine range, flags, and :set gdefault?
Part of a longer word changesSubstring or regex matchWord boundaries and punctuation in the search pattern
E488: Trailing characters during a path substitution (Stack Overflow example)Slash-delimited command parsed incorrectlyDelimiter placement. Try a separator such as #
Pipe-delimited command fails| is an invalid separatorUse a permitted separator

The pipe-delimited form below is invalid, and with no previous substitute pattern it produces E33: No previous substitute regular expression:

:s|foo|bar|

If the replacement count is off, check gdefault directly:

:set gdefault?

For syntax details, see these help entries:

:help :substitute
:help pattern-delimiter

When find and replace needs more than one file

Vim multiple files

Project-wide changes need a different workflow.

An r/neovim commenter wrote: “Everything falls apart when it comes to multi line/multi file search & replace.”

Vim offers :grep, quickfix lists, argument lists, :cdo, and :cfdo for larger jobs. Select the files yourself and keep a way to inspect and reverse the changes across them. To rename a code symbol by programming-language semantics, use a language-aware rename instead.

NoScript Team