VI Intermediate - Buffers, Marks, and Macros
Welcome to Intermediate VI
You've mastered the basics and the essential commands. Now it's time to learn the features that separate casual VI users from power users. These techniques will dramatically increase your editing efficiency and make complex tasks simple.
What You'll Learn:
- Named buffers for managing multiple clipboards
- Advanced mark usage for navigation
- Macros for automating repetitive tasks
- Advanced search and replace patterns
- Working with multiple files
- Split windows and tabs (vim)
Understanding Buffers
When you delete or yank text in VI, it goes into a buffer. But VI actually has multiple buffers you can use to store different pieces of text.
Types of Buffers
The Unnamed Buffer (Default):
When you use dd, yy, x, etc., text goes into the unnamed buffer. This is what gets pasted with p.
Named Buffers (a-z)
You can explicitly store text in buffers named 'a' through 'z'. This gives you 26 separate clipboards!
"ayy # Yank line into buffer a
"bdd # Delete line into buffer b
"cy5j # Yank current line and 5 below into buffer c
"ap # Paste from buffer a
"bp # Paste from buffer b
"cp # Paste from buffer c
Appending to Named Buffers
Use uppercase letter to append instead of replace:
"ayy # Yank line into buffer a
3j # Move down 3 lines
"Ayy # Append this line to buffer a (now has 2 lines)
5j # Move down 5
"Ayy # Append another line (now has 3 lines)
"ap # Paste all 3 lines from buffer a
The Numbered Buffers (0-9)
VI automatically maintains a history of your last 9 deletions:
| Buffer |
Contents |
"0 |
Most recent yank (only yank, not delete) |
"1 |
Most recent delete |
"2 |
Second most recent delete |
"3-"9 |
Older deletions |
dd # Delete line (goes into "1)
dd # Delete another (previous moves to "2)
"1p # Paste second-to-last deletion
"2p # Paste third-to-last deletion
PRO TIP: Use "0p to paste your last yank even after deleting something else. Since deletes don't affect buffer 0, your yanked text is safe!
Viewing Buffer Contents
:reg # View all registers/buffers
:reg a # View contents of buffer a
:reg abc # View buffers a, b, and c
PRACTICAL EXAMPLE: Reorganizing Code
# Save three different sections for later
"ayy # Yank import statements to buffer a
/class # Find class definition
"byy # Yank to buffer b
/def main # Find main function
"cyy # Yank to buffer c
# Now paste them in different order
G # Go to end
"cp # Paste main function
"bp # Paste class
"ap # Paste imports
TRY IT NOW: Create a file with 5 different lines. Yank each line into buffers a, b, c, d, e using "ayy, etc. Then paste them in reverse order: "ep "dp "cp "bp "ap
Advanced Mark Usage
You learned basic marks earlier. Now let's explore their full power.
Local vs Global Marks
| Mark Type |
Letters |
Scope |
| Local marks |
a-z |
Current file only |
| Global marks |
A-Z |
Across all files |
Setting and Using Marks
ma # Set local mark a
mB # Set global mark B (works across files)
'a # Jump to line of mark a
`a # Jump to exact position (line and column) of mark a
'B # Jump to mark B (even in another file)
Special Automatic Marks
| Mark |
Meaning |
'' |
Position before last jump |
`` |
Exact position before last jump |
'. |
Position of last change |
'[ |
Start of last change or yank |
'] |
End of last change or yank |
'^ |
Position of last insert |
'" |
Position when last exited file |
Operating on Marks
You can use marks as targets for operators:
ma # Set mark a at current position
10j # Move down 10 lines
d'a # Delete from current line to mark a
y`a # Yank from current position to exact mark a position
PRACTICAL EXAMPLE: Extracting a Function
/def process # Find function start
ma # Mark the start
/^def # Find next function (end of current)
k # Go up one line
mb # Mark the end
:'a,'b write function.py # Write marked range to file
:'a,'b delete # Delete the marked range
Smart Mark Usage:
- Use
ma before big jumps so you can return with 'a
- Use capital letters for files you frequently edit (
mV in vimrc, mB in bashrc)
- Use
'' to toggle between two locations
TRY IT NOW: Open two files. In first file, set mark A with mA. Open second file with :e file2. Set mark B with mB. Jump back to first file with 'A. Jump to second with 'B.
Macros - Automating Repetitive Tasks
Macros let you record a sequence of commands and replay them. This is one of VI's most powerful features.
Recording and Playing Macros
qa # Start recording macro into register a
(perform your commands)
q # Stop recording
@a # Play macro a once
5@a # Play macro a 5 times
@@ # Repeat last played macro
Basic Macro Example
Task: Add semicolons to end of multiple lines
qa # Start recording to register a
A; # Append semicolon to end of line
ESC # Back to command mode
j # Move to next line
q # Stop recording
# Now apply to remaining lines:
10@a # Apply to next 10 lines
More Complex Macro Examples
EXAMPLE 1: Convert list items to numbered list
# Starting text:
- Item one
- Item two
- Item three
qa # Start recording
^ # Go to start of line
x # Delete the dash
i1. # Insert "1. "
ESC # Back to command
j # Next line
^ # Start of line
x # Delete dash
i2. # Insert "2. "
ESC
j
q # Stop recording
# Apply to rest:
@a # Continues with 3., 4., etc.
EXAMPLE 2: Quote and comma-separate values
# Starting text:
apple
banana
cherry
qa # Start recording
I" # Insert quote at start
ESC
A", # Append quote and comma
ESC
j # Next line
q # Stop
10@a # Apply to next 10 lines
# Result:
"apple",
"banana",
"cherry",
EXAMPLE 3: Reformatting Log Entries
# Convert this:
2024-01-15 10:23:45 ERROR Something failed
2024-01-15 10:24:12 INFO Process started
# To this:
[ERROR] 2024-01-15 Something failed
[INFO] 2024-01-15 Process started
qa # Start recording
^ # Start of line
11l # Move right 11 chars (past date)
9x # Delete time and space
^ # Back to start
15l # Position at ERROR/INFO
diw # Delete the word
i[ # Insert [
ESC
p # Paste ERROR/INFO
a] # Append ]
ESC
j # Next line
q # Stop
@a # Apply to remaining lines
Macro Best Practices
Making Reliable Macros:
- Start with cursor positioning (
^, 0, $)
- Use motions that work from any position (
w, f, t)
- End with positioning for next iteration (
j, +)
- Test on a few lines before applying to many
- Use
:reg a to view macro contents before executing
Common Macro Mistakes:
- Not positioning cursor consistently at start
- Using search that might fail on some lines
- Forgetting to move to next line at end
- Recording
q at end (stops recording but recorded in macro)
Editing Macros
You can edit a recorded macro by pasting it, editing, and yanking back:
"ap # Paste macro from register a
(edit the text)
"ayy # Yank back into register a
# Or directly edit:
:let @a='new macro content'
TRY IT NOW: Create a file with 10 lines. Record a macro in register q that: goes to start of line (^), inserts "TODO: " (iTODO: ), returns to command mode (ESC), moves to next line (j). Play it on all lines: 9@q
Advanced Search and Replace
Beyond basic substitution, VI offers powerful pattern matching and replacement features.
Regular Expression Patterns
| Pattern |
Meaning |
. |
Any single character |
* |
Zero or more of previous |
\+ |
One or more of previous (vim) |
\? |
Zero or one of previous (vim) |
^ |
Start of line |
$ |
End of line |
\< |
Start of word |
\> |
End of word |
[ ] |
Character class |
[^ ] |
Negated character class |
\( \) |
Grouping |
\1 \2 \3 |
Backreferences to groups |
Practical Search/Replace Examples
# Remove trailing whitespace
:%s/\s\+$//g
# Remove blank lines
:g/^$/d
# Remove all lines containing "DEBUG"
:g/DEBUG/d
# Keep only lines containing "ERROR"
:v/ERROR/d
# Add line numbers to each line
:%s/^/\=line('.') . '. '/
# Swap two words
:%s/\(foo\)\(.*\)\(bar\)/\3\2\1/g
# Convert dates from MM/DD/YYYY to YYYY-MM-DD
:%s/\(\d\{2}\)\/\(\d\{2}\)\/\(\d\{4}\)/\3-\1-\2/g
# Convert snake_case to camelCase
:%s/_\([a-z]\)/\u\1/g
# Add quotes around each word
:%s/\w\+/"&"/g
# Remove HTML tags
:%s/>[^<]*<//g
# Comment out all lines
:%s/^/# /
# Uncomment all lines (remove # at start)
:%s/^# //
# Convert tabs to 4 spaces
:%s/\t/ /g
# Remove duplicate blank lines
:%s/\n\n\+/\r\r/g
# Capitalize first letter of each line
:%s/^./\u&/
# Extract email addresses (basic)
:%s/.*\([a-zA-Z0-9._-]\+@[a-zA-Z0-9.-]\+\).*/\1/
The Global Command
The :g command is incredibly powerful for operating on lines matching a pattern:
:g/pattern/command # Execute command on lines matching pattern
:g!/pattern/command # Execute on lines NOT matching
:v/pattern/command # Same as g! (inverse)
# Examples:
:g/ERROR/d # Delete all lines with ERROR
:g/TODO/move$ # Move all TODO lines to end
:g/^#/d # Delete all comment lines
:g/foo/s/bar/baz/g # On lines with "foo", replace bar with baz
:v/import/d # Delete lines without "import"
:g/^$/d # Delete empty lines
PRACTICAL EXAMPLE: Cleaning a Log File
# Remove DEBUG lines
:g/DEBUG/d
# Remove empty lines
:g/^$/d
# Extract only ERROR messages
:v/ERROR/d
# Remove timestamps (assume they're at start of line)
:%s/^\d\{4}-\d\{2}-\d\{2} \d\{2}:\d\{2}:\d\{2} //
# Sort remaining lines
:%!sort
# Remove duplicates
:%!uniq
TRY IT NOW: Create a file with various lines including some with "test" and some empty lines. Try: :g/test/d to delete test lines, undo with u, then try :v/test/d to delete non-test lines.
Working with Multiple Files
VI can handle multiple files efficiently.
Opening Multiple Files
vi file1.txt file2.txt file3.txt
Navigating Between Files
| Command |
Action |
:n |
Next file |
:prev |
Previous file |
:first |
First file |
:last |
Last file |
:args |
List all files |
:e file |
Edit another file |
:e# |
Edit alternate file (toggle) |
Editing Multiple Files
# Open multiple files
vi *.conf
# Make same change in all files
:args # See file list
:argdo %s/old/new/ge | update
# e flag: no error if pattern not found
# update: save only if modified
# Or with g command:
:argdo g/pattern/d | update
PRACTICAL EXAMPLE: Update Config Files
# Update all config files in directory
vi /etc/myapp/*.conf
# Replace old server address in all files
:argdo %s/oldserver.com/newserver.com/ge | update
# Check what was changed
:args
:prev
:n
Split Windows and Tabs (VIM)
VIM extends VI with split windows and tabs for viewing multiple files simultaneously.
Split Windows
| Command |
Action |
:split or :sp |
Split window horizontally |
:vsplit or :vsp |
Split window vertically |
:sp file |
Split and open file |
Ctrl+w w |
Switch to next window |
Ctrl+w h/j/k/l |
Move to window left/down/up/right |
Ctrl+w = |
Make all windows equal size |
Ctrl+w _ |
Maximize current window height |
Ctrl+w | |
Maximize current window width |
:q |
Close current window |
:only |
Close all but current window |
Tabs (VIM)
| Command |
Action |
:tabnew |
New tab |
:tabnew file |
Open file in new tab |
:tabn or gt |
Next tab |
:tabp or gT |
Previous tab |
:tabfirst |
First tab |
:tablast |
Last tab |
:tabclose |
Close current tab |
:tabonly |
Close all but current tab |
# Open vim with multiple tabs
vim -p file1 file2 file3
# Split current file
:sp # Horizontal split
:vsp # Vertical split
# Navigate splits
Ctrl+w h # Left window
Ctrl+w l # Right window
Ctrl+w j # Down window
Ctrl+w k # Up window
TRY IT NOW (VIM): Open vim with a file. Split with :sp. Switch windows with Ctrl+w w. Open another file in bottom with :e file2. Try vertical split: :vsp file3.
Combining Techniques - Power Workflows
WORKFLOW 1: Refactor Variable Name Across Files
# Open all Python files
vim *.py
# Use argdo to change in all files
:argdo %s/\<oldVar\>/newVar/ge | update
# Verify changes
:first
:args
:n (navigate through files)
WORKFLOW 2: Extract and Reorganize Config
# Extract all port configurations
:g/port/y A # Yank lines with "port" and append to register a
# Open new file
:e ports.conf
# Paste collected lines
"ap
# Sort them
:%!sort -u
# Save
:w
WORKFLOW 3: Macro + Buffer Workflow
# Record macro to extract function names
qa
/def # Find function
w # Move to function name
"Ayw # Append function name to register a
n # Next occurrence
q
# Apply to all functions
50@a
# Create index file
:e function_index.txt
"ap # Paste all collected names
:%!sort # Sort them
:%s/$/(),/ # Add parentheses and comma
:wq
WORKFLOW 4: Complex Log Analysis
# Start with large log file
:e production.log
# Extract errors to new buffer
:g/ERROR/y A
# Open error analysis file
:split errors.txt
"ap # Paste errors
# Extract just the error codes
:%s/.*ERROR \(\d\+\).*/\1/
# Sort and count
:%!sort | uniq -c | sort -rn
# Save
:w
Command-Line Tricks
VI's command line (Last Line Mode) has many powerful features.
Command History
: # Enter command mode
<UP> # Previous command
<DOWN> # Next command
q: # Open command history window (vim)
Ranges
| Range |
Meaning |
: |
Current line |
:5 |
Line 5 |
:5,10 |
Lines 5 through 10 |
:.,10 |
Current line through 10 |
:.,$ |
Current line to end |
:% |
All lines |
:'a,'b |
From mark a to mark b |
:.+5 |
Current line plus 5 |
External Commands
:!ls -la # Run shell command
:r !date # Insert command output
:%!sort # Filter file through command
:5,10!column -t # Format lines 5-10 as table
:'a,'b!sort # Sort marked range
# Common filters
:%!sort # Sort file
:%!sort -u # Sort and remove duplicates
:%!nl # Number lines
:%!column -t # Column format
:%!jq . # Format JSON (if jq installed)
:%!xmllint --format - # Format XML
TRY IT NOW: Create a file with unsorted lines. Use :%!sort to sort them. Undo with u. Add line numbers with :%!nl.
Real-World Intermediate Scenarios
SCENARIO 1: Batch Rename Variables in Multiple Files
vim *.c
:argdo %s/\<old_func\>/new_func/ge | update
SCENARIO 2: Extract Configuration Values
:g/^server/y A # Collect all server lines
:e servers.txt # New file
"ap # Paste collected lines
:%s/.*=\s*// # Remove everything before =
:%!sort -u # Sort and unique
:wq
SCENARIO 3: Create Table of Contents with Marks
# Set marks at important sections
/Introduction
mI
/Configuration
mC
/Troubleshooting
mT
# Later, jump instantly:
'I # Jump to Introduction
'C # Jump to Configuration
'T # Jump to Troubleshooting
SCENARIO 4: Macro for Test Case Generation
# Record macro to create test function template
qa
odef test_():
"""Test """
assert True
0k$
q
# Generate 10 test templates
10@a
# Fill in names manually or with another macro
Performance and Efficiency Tips
Speed Techniques:
- Use
* to search word under cursor instead of typing /word
- Use
. to repeat changes instead of macros for simple tasks
- Use named buffers to juggle multiple pieces of text
- Set marks before big jumps so you can return easily
- Use
:g and :v instead of manual search/delete
- Use
:argdo for batch operations instead of opening files one by one
Memory Aids:
- Buffers: "a through z = your personal clipboards
- Marks: lowercase = local, uppercase = global
- Macros: Always start with positioning (
^, 0)
- Substitute: g = global, c = confirm, i = ignore case
What's Next?
You now have intermediate VI skills. You can:
- Use named buffers to manage multiple clipboards
- Navigate efficiently with marks
- Automate repetitive tasks with macros
- Perform complex search and replace operations
- Work with multiple files efficiently
- Use split windows and tabs
- Combine techniques for powerful workflows
The next tutorial covers advanced topics: ex mode in depth, customization, and power user techniques.
Created for Linux System Administrators | Part 3 of the VI Learning Series
Master these techniques and you'll be a VI power user!
← Back to VI Index
↑ Back to EXPANDED