Macros and Registers
Summary: in this tutorial, you will learn automate repetitive edits with macros and master vim's register system for advanced clipboard management and text manipulation.
Macros and Registers
Sometimes you need to make the same edit over and over — renaming a pattern across 50 lines, reformatting a data file, or adding the same code structure repeatedly. Instead of doing it manually each time, you can record a macro — a sequence of keystrokes that Vim plays back for you.
Macros are stored in registers — Vim's system of named clipboards. Understanding registers also unlocks advanced copy/paste workflows.
What you'll learn in this tutorial:
- How to record and play back macros to automate repetitive edits
- How to run a macro on many lines at once
- What registers are and how they store different types of text
- How to use multiple clipboards (named registers) to copy several things at once
- Special registers that Vim maintains automatically
- Practical recipes you can use right away
What Is a Macro?
A macro is a recording of keystrokes. You press "record," perform some edits, press "stop," and then you can replay those exact edits as many times as you want. It's like a tape recorder for your keyboard.
Think of it like this: if you needed to add a semicolon to the end of 100 lines, you could:
- Record yourself going to the end of a line and adding a semicolon (3 keystrokes)
- Play that recording back 99 times
That's a macro.
Recording a Macro
Step-by-Step
Step 1: In Normal mode, press q followed by a letter to start recording. The letter is the name of the register where the macro will be stored. For example, qa starts recording into register a.
Step 2: You'll see recording @a at the bottom of the screen. Now perform your edits — every keystroke is being recorded.
Step 3: Press q again to stop recording.
qa " Start recording into register 'a'
" (now do your edits — everything is recorded)
q " Stop recordingPlaying Back a Macro
Press @ followed by the register letter to play back the macro:
@a " Play the macro stored in register 'a'
@@ " Repeat the last macro you played (shortcut!)Running a Macro Multiple Times
Put a number before @ to repeat the macro that many times:
10@a " Play macro 'a' ten times
100@a " Play it 100 timesIf a macro fails on one line, it stops. Vim is smart — if your macro tries to do something impossible (like searching for text that doesn't exist), it stops rather than continuing blindly. This is actually helpful because it prevents incorrect edits.
Practical Macro Example
Let's say you have a list of names and you want to wrap each one in quotes and add a comma:
Starting text:
Alice
Bob
Charlie
Dave
Goal:
"Alice",
"Bob",
"Charlie",
"Dave",
Here's how to record a macro for this:
qa " Start recording into register 'a'
I"<Esc> " Go to the start of the line, insert a quote, back to Normal
A",<Esc> " Go to the end of the line, append a quote and comma, back to Normal
j " Move down one line (positioning for the next repetition)
q " Stop recordingNow play it on the remaining lines:
3@a " Play the macro 3 times (for Bob, Charlie, Dave)Why include j (move down) in the macro? Because when you replay the macro, you want it to automatically move to the next line. Without j, the macro would edit the same line over and over. Including the movement at the end makes repeating the macro seamless.
Macro Tips
Start at a Consistent Position
Before recording, move your cursor to a predictable position (like the beginning of the line with 0 or ^). This ensures the macro works correctly on every line, regardless of where your cursor starts:
qa " Start recording
0 " Go to the beginning of the line (consistent start)
" ... do your edits ...
j " Move to the next line
q " Stop recordingUse Search in Macros
You can include search commands in macros. This is powerful for jumping to specific patterns:
qa " Start recording
/TODO<CR> " Search for "TODO" (jumps to the next one)
ciwDONE<Esc> " Change the word to "DONE"
q " Stop recording
100@a " Run the macro 100 times — changes every TODO to DONERunning a Macro on Selected Lines
You can combine macros with Visual mode to run a macro on every selected line:
V " Start line selection
5j " Select 6 lines
:normal @a " Run macro 'a' on every selected lineWhen you press : in Visual mode, Vim types :'<,'> for you (meaning "the selected range"). Just add normal @a after it and press Enter. The :normal command runs Normal mode commands on each line in the range.
Editing a Macro
If your macro has a mistake, you don't have to re-record it. Since macros are stored in registers, you can paste the register contents, edit it, and yank it back:
" Paste the macro from register 'a' into your file
"ap " This pastes the raw keystrokes as text
" Edit the text (fix the mistake)
" Yank it back into register 'a'
0"ay$ " Go to start of line, yank to end into register 'a'
" Delete the line you just used for editing
ddAppending to a Macro
To add more steps to an existing macro without re-recording the whole thing, use a capital letter when recording:
qA " Record into register 'a' (APPEND mode — capital A)
" Additional keystrokes are added to the end
q " StopWhat Are Registers?
Registers are named storage slots in Vim. When you delete or yank text, it goes into a register. When you paste, you're pulling from a register. Macros also live in registers.
You can think of registers as 26 clipboards (one for each letter) plus some special ones.
Viewing Registers
:registers " Show all registers and their contents (or :reg for short)This shows something like:
--- Registers ---
"" the last text you deleted or yanked (default register)
"0 the last text you yanked
"1 the last text you deleted (previous deletes shift to "2, "3, etc.)
"a whatever you stored in register a
"+ system clipboard
Using Named Registers
By default, when you yank or delete, text goes into the unnamed register (""). But you can specify a named register with " followed by a letter:
" Yank into register 'a'
"ayy " Yank the current line into register 'a'
" Yank into register 'b'
"byiw " Yank the current word into register 'b'
" Paste from register 'a'
"ap " Paste what's in register 'a'
" Paste from register 'b'
"bp " Paste what's in register 'b'The format is: " + register name + operator
Why Use Named Registers?
Named registers let you store multiple pieces of text at the same time. Without them, every time you delete or yank something, it replaces what was in the clipboard before. With named registers:
" Copy three different things
"ayy " Line 1 goes into register 'a'
j"byy " Line 2 goes into register 'b'
j"cyy " Line 3 goes into register 'c'
" Now paste any of them wherever you want
"ap " Paste register 'a'
"bp " Paste register 'b'
"cp " Paste register 'c'Appending to a Register
Use a capital letter to add to an existing register instead of replacing its contents:
"ayy " Yank line into register 'a' (replaces whatever was there)
"Ayy " Yank line and APPEND it to register 'a' (adds to existing content)This is useful for collecting lines from different parts of a file into one register.
Special Registers
Vim has several special registers that are managed automatically:
| Register | Name | What It Contains |
|---|---|---|
"" | Unnamed | The last delete or yank (this is the default) |
"0 | Yank | The last yank only (not affected by deletes) |
"1-"9 | Numbered | Recent deletes (1 = most recent, 9 = oldest) |
"+ | System clipboard | Your operating system's clipboard |
"* | Selection | Primary selection (Linux: middle-click paste) |
"/ | Search | The last search pattern |
". | Last insert | The text you last typed in Insert mode |
"% | Filename | The name of the current file |
": | Command | The last command-line command you ran |
"_ | Black hole | Text sent here is truly deleted (not saved anywhere) |
The Yank Register ("0) — Very Useful!
Here's a common frustration: you yank a line, then delete something else, and now you can't paste the original text because the delete replaced it in the default register.
Solution: The yank register ("0) always contains your last yank, unaffected by deletes:
yy " Yank a line — it goes to "" AND "0
dd " Delete a line — it goes to "" (replacing the yank) but NOT "0
"0p " Paste from "0 — this has your original yanked text!The Black Hole Register ("_) — Delete Without Saving
Sometimes you want to delete text without it replacing your clipboard. Use the black hole register:
"_dd " Delete this line but don't save it anywhere
"_diw " Delete this word — the unnamed register is untouchedThe System Clipboard Register ("+)
To copy text to your system clipboard (so you can paste it in other applications):
"+yy " Yank current line to system clipboard
"+p " Paste from system clipboardIf you added set clipboard=unnamedplus to your vimrc (from the configuration tutorial), Vim automatically uses the system clipboard for all yanks and deletes. You don't need the "+ prefix — yy and p work directly with your system clipboard.
Inserting Register Contents in Insert Mode
While in Insert mode, press Ctrl-r followed by a register name to paste register contents:
" In Insert mode:
Ctrl-r a " Insert contents of register 'a'
Ctrl-r 0 " Insert last yanked text
Ctrl-r + " Insert system clipboard
Ctrl-r / " Insert last search pattern
Ctrl-r % " Insert current filename
Ctrl-r =5*3<CR> " Insert the result of a math expression (15)That last one (Ctrl-r =) is the expression register — you can type any math expression and Vim calculates the result!
Practical Recipes
Recipe 1: Convert a List to an Array
Starting text:
apple
banana
cherry
Goal:
["apple", "banana", "cherry"]qa " Record macro
I"<Esc> " Add opening quote at start
A",<Esc> " Add closing quote and comma at end
J " Join with the next line
q " Stop recording
2@a " Run twice (for banana and cherry)
I[<Esc> " Add opening bracket
$x " Remove trailing comma
A]<Esc> " Add closing bracketRecipe 2: Add Line Numbers
Starting text:
First item
Second item
Third item
Goal:
1. First item
2. Second item
3. Third item
" Use a Vim command instead of a macro:
:%s/^/\=line('.').'. '/This means: on every line (%), replace the beginning of the line (^) with the line number (line('.')) followed by . .
Recipe 3: Swap First and Last Name
Starting text:
John Smith
Jane Doe
Bob Wilson
Goal:
Smith, John
Doe, Jane
Wilson, Bob
qa " Record macro
0 " Go to start of line
dw " Delete the first name (including space)
$ " Go to end of line
a, <Esc> " Append ", " after the last name
p " Paste the first name
0x " Go to start and delete the extra space (if any)
j " Move to next line
q " Stop recording
2@a " Run on remaining linesRecipe 4: Collect All TODO Comments
" Clear register 'a'
qaq " Record empty macro into 'a' (clears it)
" Yank all lines containing TODO into register 'a'
:g/TODO/"Ayy
" Paste them
"apThe :g/TODO/"Ayy command means: on every line matching "TODO", append-yank ("Ayy) that line into register a.
Summary
Here's what you've learned:
- Record macros with
q{letter}, stop withq, play with@{letter} - Repeat with
@@(last macro) or10@a(10 times) - Include movement (
j) at the end of macros for seamless repetition - Start macros at a consistent position (
0or^) - Run macros on visual selections:
:'<,'>normal @a - Registers are named clipboards:
"athrough"z - Store in a register:
"ayy(yank toa), paste from it:"ap - Append to a register with a capital letter:
"Ayy "0always has your last yank (even after deletes)"_is the black hole — deletes without saving"+is the system clipboardCtrl-r {register}pastes register contents in Insert modeCtrl-r =evaluates math expressions in Insert mode
Practice: Macros and Registers
Create a practice file:
vim macro-practice.txtPress i, type the following, then press Escape:
name: Alice
name: Bob
name: Charlie
name: Dave
name: Eve
TODO fix the login bug
TODO add unit tests
TODO update documentation
Now try these tasks:
- Record a macro that changes
name:touser:on a line:qa→0cw user:<Esc>j→q - Play the macro on the remaining name lines:
4@a - Yank the first line into register
a:"ayy - Yank the third line into register
b: move to line 3,"byy - Paste from register
aat the bottom: go to last line,"ap - Paste from register
bbelow that:"bp - Check your registers:
:reg - Record a macro to change
TODOtoDONE:qb→/TODO<CR>cwDONE<Esc>→q - Play it to change the remaining TODOs:
2@b - Use the expression register in Insert mode: press
i, thenCtrl-r =, type10*5, press Enter
Show Solution
" 1. Record macro to change "name:" to "user:"
" Move to the first "name:" line
qa " Start recording into register 'a'
0 " Go to the start of the line
cw " Change the first word
user:<Esc> " Type "user:" and return to Normal mode
j " Move down to the next line
q " Stop recording
" 2. Play macro on remaining lines
4@a " Runs the macro 4 times (Bob, Charlie, Dave, Eve)
" All "name:" are now "user:"
" 3. Yank first line into register 'a'
gg " Go to first line
"ayy " Yank into register 'a'
" 4. Yank third line into register 'b'
3G " Go to line 3
"byy " Yank into register 'b'
" 5 & 6. Paste at the bottom
G " Go to the last line
"ap " Paste register 'a' below
"bp " Paste register 'b' below
" 7. Check registers
:reg " Shows all registers and their contents
" You'll see register "a has the first line and "b has the third line
" 8. Record macro to change TODO to DONE
qb " Start recording into register 'b'
/TODO<CR> " Search for the next "TODO"
cwDONE<Esc> " Change the word to "DONE"
q " Stop recording
" 9. Play the macro for remaining TODOs
2@b " Runs twice — changes the other two TODOs
" 10. Expression register
i " Enter Insert mode
Ctrl-r = " Opens the expression prompt
10*5<CR> " Type the expression and press Enter
" "50" appears in your text!
<Esc> " Back to Normal mode
:q! " Quit without savingWritten by the ShellRAG Team
The ShellRAG editorial team writes practical, beginner-friendly Vim tutorials with tested code examples and real-world use cases. Every article is technically reviewed for accuracy and updated regularly.
Learn more about us →