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:

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:
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:
  1. Start with cursor positioning (^, 0, $)
  2. Use motions that work from any position (w, f, t)
  3. End with positioning for next iteration (j, +)
  4. Test on a few lines before applying to many
  5. Use :reg a to view macro contents before executing
Common Macro Mistakes:

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:
Memory Aids:

What's Next?

You now have intermediate VI skills. You can:

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