Change, Replace, and Substitute in Vim: How to Pick the Right Command

LinuxForDevices featured banner for the Vim change, replace and substitute guide, showing one cursor position branching into three kinds of edit

Vim’s change, replace, and substitute commands overlap on purpose, and which one you press is decided by what you already know about the edit.

Replace takes a character, change takes a motion, and substitute takes a count, so the command whose argument you can already name is the one I reach for.

What separates change, replace, and substitute

All three edit the buffer, and all three hand control back when the work is done. What separates them is the thing each one waits for before it starts working.

That argument is what you settle before you touch the keyboard, so name it and the choice makes itself. I keep the same table in mind whenever I open a config file to fix something specific.

CommandWaits forEnds inReach for it when
rone characternormal modea single character is wrong
Rthe characters you typereplace modethe replacement is the same length
ca motioninsert modeyou know where the edit stops
sa count of charactersinsert modeyou know how many characters go
Sa count of linesinsert modewhole lines go
:sa search string and a rangenormal modethe text names the target, not the position

Read the second column first, because it decides everything in the columns after it.

Vim’s own reference lists s as a synonym for cl and S as a synonym for cc, which is the same rule stated from the other end of the keyboard. The destination column is the other half of it, and it is where the normal mode family splits in two.

On that list, two commands leave the cursor in normal mode and four leave it in insert mode. The r command is the one that never touches a register either, which is the difference that shows up later when a change is followed by a paste.

If the editor itself is new to you, the Vim tutorial covers the modes and movements this walkthrough assumes.

Pick the wrong one and the symptom is not an error, which is what keeps the family confusing. You land in insert mode when you expected to stay in normal mode, and the next keystroke goes into the file instead of doing what you meant.

What you need before the first keystroke

Nothing here needs a plugin, a config line, or a newer build.

I ran every sequence in this walkthrough against Vim 9.1 and captured the screen each time. What you see below is the editor’s own output rather than a tidied transcript.

  • Vim installed and working. Run vim –version in a terminal to see which build you have.
  • A text file you are happy to change. The walkthrough uses one small config file with a few deliberate mistakes in it.
  • Normal mode as your starting point, so press Escape once before the first command.
  • A copy of the file on disk, so you can compare your result with the finished version at the end.

The commands here are old Vim rather than new Vim, so an older build behaves in the same way. Nothing below depends on a feature that arrived late.

The practice file is a plain text config, and editing files in Linux covers the wider toolset if you want an alternative to Vim.

The showmode option decides how you will read the screenshots in this walkthrough. It is on by default, and it is what puts the mode indicator in the bottom right corner of the screen.

That indicator is the cheapest way to tell whether a command left you in insert mode or handed you back to normal mode, and it is the state I watch in every frame below.

Replace a character without leaving normal mode

Reach for r when the cursor already sits on the character that is wrong, because it is the only command here that finishes the job without changing mode.

A single character, no mode change

The r command takes the next character you type and puts it where the cursor is, then hands control back to normal mode. That hand-back is the whole reason to prefer r over s for a one-character fix, because there is no insert mode to escape afterwards.

/app-lokl
7l
ri

The search lands on the a of app, 7l walks the cursor to the last letter of the mistyped word, and ri swaps that letter for an i.

The r command replacing the capital T in The with a lowercase t, shown before and after
The rt sequence swaps one character and leaves the cursor in normal mode

Nothing moves apart from the one character. The cursor stays where it was, and the surrounding text is untouched.

Undo treats it as a single change, so a misplaced r costs one press of u. I checked that after masking a value, and Vim reported one change and restored the line intact.

If you do end up in insert mode by accident, exiting Vim covers the ways back to normal mode.

A count blanks a run in place

Give r a count and Vim replaces that many characters with that many copies of the same letter. Masking a secret is the natural use, because the line keeps its length.

/kf83nz
6r*

The six characters become six asterisks, and the equals sign and the spacing in front of them stay exactly as they were.

The count is a hard promise rather than a request, and Vim replaces the number of characters you asked for without checking where the word ends. A count longer than the word will eat into whatever follows it on the line, so the count is worth reading twice.

Replace mode overwrites instead of inserting

Capital R opens Replace mode, where each character you type destroys the one under the cursor instead of pushing the rest of the line to the right.

A same-length swap therefore never disturbs anything to the right of the run, which is why it suits a word buried in the middle of an indented line.

/debug
Rtrace
Vim in Replace mode overwriting the word debug with trace, with the REPLACE indicator on the status line
Replace mode overwrites in place and shows its own indicator in the bottom right

The mode indicator in the bottom right corner is the state to watch, and Escape is what ends it.

Press backspace inside Replace mode and the original character returns, one press at a time. I tested that against a fumbled overwrite and the text came back exactly as it was.

The command to avoid here is r on a value whose length is going to change. It replaces exactly the characters you asked for and cannot make the line longer or shorter.

That is the boundary between r and s, where one swaps a character for a character and the other trades a run of them for whatever you type next.

The virtual variant is worth knowing about when a tab is involved. The gR command replaces in screen space rather than in file space, so a single tab can overwrite several characters at once.

Change deletes up to a motion

Change is the command for the case where you know where an edit stops but not how long it is. My rule of thumb is to ask that question first, and to fall back to a count only when I cannot answer it.

It shares its deletion machinery with d, and the split between them is one word. Change enters insert mode afterwards and delete does not.

cw stops at the end of the word

The c command takes a motion, deletes everything the motion covers, and drops you into insert mode.

A word motion stops at the boundary rather than the space, and that boundary is where the surprises live.

/redis
cw
The cw command removing the word The and leaving the space in front of the next word
cw removes the word and leaves the space in front of it

Vim reads cw as change-word, and a word does not include the white space after it, so the separator survives the deletion.

The insertion point ends up right after the equals sign and before the surviving space. That is why the line in the figure reads one column short of a finished edit.

Other motions worth keeping

The same letter works with any motion, and a few of them cover the common cases.

SequenceWhat it changes
ciwthe word under the cursor, ignoring the space around it
cawthe word plus the space after it
ct,everything up to the next comma, leaving the comma
c$ or Ceverything from the cursor to the end of the line
ccthe whole line

Whether a space leaves with the word is the difference between the top two rows, and it decides how the rest of the line reads afterwards.

I ran ciw against a value in the middle of a line and it replaced the word while leaving the padding either side untouched. That is the behaviour the inner-word motion exists to give you, and it is why the plain word motion keeps catching people out.

cc and C are not the same command

Both delete text and both leave you in insert mode, and they part company on how much of the line they take with them.

cc takes the whole line, while C takes only the part from the cursor onwards.

/backend
ccbackend      = memcached

On an indented line the difference is visible. Replacing with C leaves the leading whitespace in place and gives you a short line, while the linewise form starts you on a fresh line with the old indent preserved.

Vim’s reference marks C as a synonym for c$ and S as a synonym for cc, so the linewise tag is the whole distinction between two commands that look interchangeable at the keyboard.

Substitute deletes a count of characters

Substitute is the narrowest of the three, and its argument is the one that gets misread, so it is worth naming carefully.

Lowercase s is cl with a count

Lowercase s deletes the character under the cursor and enters insert mode, so Vim documents it as a synonym for cl. Add a count and it deletes that many characters instead, which makes the count the entire argument.

/8080
4s443
The 3s sequence removing three characters and entering insert mode
A count with s removes that many characters and enters insert mode

The four characters go, three arrive, and the equals sign and its surrounding spaces are untouched.

That is the command to reach for when a value changes length and you know the length of the old one. You never have to describe where it ends, only how far it runs.

Compare that with r, which needs the replacement to be the same length. Substitute is the one that can shrink a word, and change is the one that can grow it.

Capital S takes lines

Capital S is a synonym for cc, so its count is a count of lines rather than a count of characters. It is the same linewise behaviour described above, reached from the substitute side of the family.

The two commands are worth keeping apart in your head, because the caps lock key is the only thing separating them and the failure is silent.

Where the deleted text goes

Every command in this walkthrough except r drops what it removed into a register, and the unnamed register is what a plain paste reads.

I checked the registers after a cw on the config file. The deleted word was sitting in the unnamed register with the replacement text in the last-insert register beside it.

That is the mechanism behind a surprise people hit when they change a word and then press p, because the paste delivers the text they just removed.

The Vim registers guide covers the named and numbered ones in depth if you want to keep more than one deletion around.

Use a named register such as “a when the removed text has to survive the next edit. Use r when you want no register touched at all.

The Ex substitute command answers a different question

Everything so far picks the edit by position. The colon command picks it by content instead.

:s replaces matches, not characters

The colon command is a different tool from the normal-mode letter, because it takes a search string, a replacement, and a range.

:%s/lokl/loki/g
Vim reporting four substitutions on four lines after running the Ex substitute command for lokl to loki
The Ex substitute command reports how many lines it changed

The percent sign means the whole file, and the g flag means every match on each line rather than the first.

Vim prints the count on the last line once the change is bigger than the report threshold, which is where that message comes from. A smaller edit reports nothing at all, so silence is not the same as a failure, and that is worth remembering the next time a substitution seems to do nothing.

The range is the setting you leave alone, and it changes where the command applies, so it is worth a look before you run a substitution on a file you care about. Leaving the percent sign off restricts it to the current line, and a numeric range or a visual selection narrows it further.

Flags that change what gets replaced

The flags are where this command earns its keep, and a few of them cover the common runs.

FlagEffect
gevery match on each line, not only the first
cask before each replacement
iignore case in the search string
estay silent when nothing matches

The c flag turns the command into a review pass, which is what you want on an unfamiliar file.

:%s/lokl/loki/gc
Vim asking replace with loki, y for yes or n for no, at the first match after adding the c flag
The c flag stops at every match and asks before replacing

Each match stops for a keystroke, and pressing a at the prompt accepts the rest of them without further questions. I ran that against a file where the search string appeared in more than one place, and Vim stopped at every match.

When the target is a position rather than a piece of text, the normal-mode letters are shorter to type. My guide to search and replace in Vim covers the wider regular expression side of this command.

Editing a config file end to end

The sequences above came from one small config file, so the finished result is worth seeing in full.

It starts with a mistyped hostname, a token that should not be shared, a stale port, a log level to replace, and a cache backend that changes wholesale.

Here is every command in the order I typed them.

/app-lokl
7lri

/kf83nz
6r*

/8080
4s443

/debug
Rtrace

/max_retries
f3C10

/backend
ccbackend      = memcached

:%s/lokl/loki/g
The finished deploy.conf file after seven Vim edits, with the corrected hostname, masked token, new port, new log level and new cache backend
The finished file after the full sequence of edits

The result is seven edits from seven different commands. The file never left normal mode except where a command took it there on purpose.

Each line of that sequence does something the others cannot. The searches put the cursor where the argument is, the letters decide how much of the line goes, and the colon command is the only one that reads the file rather than the cursor position.

A few boundaries show up along the way, and knowing them in advance saves a confusing minute.

  • A search string stays in the command line until the next keystroke, so a typo in the search can look like it took effect.
  • A count larger than the text available changes less than you asked for and says nothing about it.
  • cc keeps the line it replaced, so the indent question comes up the moment an indented file is involved.
  • A substitution with no match reports nothing at all, which is silence rather than failure.

The way to check your own run is to keep the original beside the new file and compare them. A misplaced count is the mistake this set of commands produces, and it shows up in a comparison immediately, so I kept the original in place while I worked through the sequence above.

The keystroke to try next

The choice stops being a decision once the motions are in your fingers.

My own habit now is to reach for c first, and I fall back to r or s only when a count is genuinely the thing I know about the edit. In practice that means the motions are what I keep practising, because everything else in this family follows from them.

Start with the motion your hand already reaches for, and check the rest against the built-in list when an edit does not fit the one you know.

The key bindings list is worth a look once the motions feel natural, and terminal text editors puts Vim next to the alternatives.

:h motion

Frequently asked questions

What is the difference between s, c, and r in Vim?

r replaces one character and stays in normal mode, s deletes a count of characters and enters insert mode, and c deletes up to a motion and enters insert mode. Vim’s reference lists s as a synonym for cl.

Does cw delete the space after the word?

No. Vim reads cw as change-word, and a word does not include the following white space, so the space survives. Use caw when the space should go with the word.

How do I replace every occurrence of a word in a file?

Use :%s/old/new/g. The percent sign covers the whole file and the g flag takes every match on each line. Add the c flag to confirm each replacement before it happens.

Which command leaves the deleted text in a register?

c, s, S, C, cc and the colon s command all put the removed text into a register, so a following paste can insert it. The r command never touches a register.