VI Advanced - Ex Commands and Customization

Welcome to Advanced VI

You've mastered the intermediate techniques. Now it's time to learn the deep power of ex commands, extensive customization options, and the techniques that make VI a complete development environment.

What You'll Master:

Understanding Ex Mode

Ex is the line editor that VI is built on top of. Understanding ex commands gives you incredible power.

Entering Ex Mode

Q # Enter ex mode (traditional vi) : # Execute single ex command :visual # Return to visual mode from ex mode
Note: Most people never enter full ex mode (Q). Instead, they use individual ex commands with :. However, understanding ex commands is crucial for advanced usage.

Ex Command Structure

:[range]command[options] # Examples: :5d # Delete line 5 :1,10d # Delete lines 1-10 :%s/old/new/g # Substitute in all lines :g/pattern/d # Delete all lines matching pattern

Advanced Ex Commands

Line Addressing

Address Meaning
. Current line
$ Last line
% All lines (same as 1,$)
n Line number n
'a Line with mark a
/pattern/ Next line matching pattern
?pattern? Previous line matching pattern
+n n lines forward from current
-n n lines backward from current

Complex Range Examples

:.,$d # Delete from current line to end :1,.d # Delete from start to current line :'a,'bd # Delete from mark a to mark b :/start/,/end/d # Delete from "start" to "end" :.+5,.+10d # Delete 5 lines ahead through 10 lines ahead :/^class/,/^def/d # Delete from "class" line to "def" line :?^import?,/^def/p # Print from last import to next def

The Copy Command

:t # Copy (t = "to") :co # Same as :t # Examples: :5t. # Copy line 5 to after current line :1,5t$ # Copy lines 1-5 to end of file :'a,'bt10 # Copy marks a-b to after line 10 :.t0 # Copy current line to start of file :/pattern/t. # Copy next line with pattern to current position

The Move Command

:m # Move # Examples: :5m. # Move line 5 to after current line :1,5m$ # Move lines 1-5 to end of file :'a,'bm10 # Move marks a-b to after line 10 :.m0 # Move current line to start of file

The Global Command Deep Dive

:g/pattern/command # Execute command on matching lines :g!/pattern/command # Execute on non-matching lines :v/pattern/command # Same as g! (inverse global) # Multiple commands with | :g/pattern/d | s/foo/bar/ # Examples: :g/TODO/m$ # Move all TODO lines to end :g/^#/t$ # Copy all comment lines to end :g/ERROR/y A # Append all ERROR lines to buffer a :g/^$/d # Delete all blank lines :v/pattern/d # Keep only lines with pattern :g/pattern/-1d # Delete line before each match :g/pattern/+1d # Delete line after each match :g/^/m0 # Reverse file (move each line to top) :g/pattern/normal @q # Run macro q on matching lines
COMPLEX EXAMPLE: Reorganize Function Definitions
# Move all private functions (starting with _) to end :g/^def _/m$ # Copy all class definitions to a new file :g/^class/w >> classes.txt # Delete all lines between "START" and "END" markers :g/START/,/END/d
TRY IT NOW: Create a file with mixed content. Use :g/ERROR/t$ to copy all ERROR lines to end. Use :v/ERROR/d to delete everything except ERROR lines (undo first to keep original).

Advanced Substitution Techniques

Substitution Flags and Modifiers

Flag Meaning
g Global (all occurrences on line)
c Confirm each substitution
i Case insensitive
I Case sensitive (override default)
e Suppress error if pattern not found
& Repeat last substitution

Advanced Replacement Patterns

# Using captured groups :%s/\(\w\+\) \(\w\+\)/\2 \1/ # Swap two words # Using special characters in replacement :%s/pattern/&/ # & = matched text :%s/\(.*\)/[\1]/ # Wrap in brackets # Case conversion (vim) :%s/\w\+/\U&/g # Uppercase matched text :%s/\w\+/\L&/g # Lowercase matched text :%s/\w\+/\u&/g # Capitalize first letter :%s/_\(\w\)/\u\1/g # snake_case to camelCase # Using expressions (vim) :%s/\d\+/\=submatch(0)+1/g # Increment all numbers :%s/^/\=line('.'). '. '/ # Add line numbers :%s/$/\=strftime("%Y-%m-%d")/ # Add date to end of lines # Complex patterns :%s/\v(\d{3})-(\d{3})-(\d{4})/(\1) \2-\3/g # Format phone numbers :%s/\v(\w+)@(\w+)\.(\w+)/<\1@\2.\3>/g # Wrap emails in <>

Substitution in Specific Contexts

# Only in lines matching pattern :g/function/s/old/new/g # Only in lines NOT matching pattern :v/comment/s/old/new/g # In a range :5,20s/old/new/g # From mark to mark :'a,'bs/old/new/g # In visual selection (automatic after V) # Select with V, then: :s/old/new/g
PRACTICAL EXAMPLE: Clean Up CSV Data
# Remove quotes :%s/"//g # Convert spaces to commas :%s/\s\+/,/g # Remove empty fields :%s/,,/,/g # Add header :1i Name,Age,City . # Quote fields with spaces :%s/\([^,]*\s[^,]*\)/"\1"/g

Text Object Manipulation

Sorting and Filtering

# Sort entire file :%!sort # Sort specific range :5,20!sort # Sort and remove duplicates :%!sort -u # Reverse sort :%!sort -r # Numeric sort :%!sort -n # Sort by column :%!sort -k2 # Sort by second column # Case-insensitive sort :%!sort -f # Sort in visual selection # Select with V, then: :!sort

Unix Command Integration

# Format as columns :%!column -t # Number lines :%!nl :%!cat -n # Remove duplicates (keeping first occurrence) :%!uniq # Count lines, words, characters :%!wc # Filter through awk :%!awk '{print $1, $3}' # Print columns 1 and 3 # Filter through sed :%!sed 's/old/new/g' # Indent with expand :%!expand -t4 # Convert tabs to 4 spaces # JSON formatting (if jq available) :%!jq . # XML formatting (if xmllint available) :%!xmllint --format - # Compress whitespace :%!tr -s ' ' # Reverse lines :%!tac :g/^/m0 # Alternative: move each line to top
PRACTICAL EXAMPLE: Log File Analysis Pipeline
# Start with raw log :e application.log # Extract just timestamps and error messages :%s/^\(\d\{4}-\d\{2}-\d\{2} \d\{2}:\d\{2}:\d\{2}\).*ERROR: \(.*\)/\1 \2/ # Remove lines that didn't match (will be unchanged) :v/^\d\{4}/d # Sort by timestamp :%!sort # Count occurrences of each error :%!uniq -c # Sort by frequency :%!sort -rn # Save result :w error_summary.txt

File and Buffer Management

Reading and Writing

:r filename # Read file after current line :r !command # Read command output :0r filename # Read file at start :$r filename # Read file at end :5r filename # Read file after line 5 # Write variations :w # Write current file :w filename # Write to filename :w >> filename # Append to filename :5,20w filename # Write lines 5-20 :'a,'bw filename # Write marked range :w !command # Pipe to command :w !sudo tee % # Save with sudo :.w !sh # Execute current line in shell :%!python # Execute file as Python # Partial file operations :e +25 filename # Open at line 25 :e +/pattern filename # Open at pattern :e filename | 25 # Open and go to line 25

File Information

:f # Show filename and position :f newname # Rename buffer Ctrl+g # Show file info 1 Ctrl+g # Show full path :file # Show file info :ls # List buffers (vim) :b3 # Switch to buffer 3 (vim) :bd # Delete buffer (vim)

Customization - The .exrc File

Your ~/.exrc (or ~/.vimrc for vim) contains your VI configuration.

Basic .exrc Structure

Sample ~/.exrc file:
" Basic settings set number " Show line numbers set autoindent " Auto-indent new lines set shiftwidth=4 " Indent width set tabstop=4 " Tab width set showmatch " Highlight matching brackets set ignorecase " Case-insensitive search set smartcase " Override ignorecase if uppercase used set hlsearch " Highlight search results set incsearch " Incremental search set ruler " Show cursor position set showmode " Show current mode set wrapscan " Search wraps around end set magic " Use magic patterns " Vi compatibility (in vim) set nocompatible " Use vim enhancements " File handling set autowrite " Auto-save before :next, :make, etc. set backup " Keep backup files set backupdir=~/.vim/backup " Backup directory " Display set nowrap " Don't wrap long lines set scrolloff=5 " Keep 5 lines visible above/below cursor set laststatus=2 " Always show status line " Editing set backspace=indent,eol,start " Allow backspace over everything set expandtab " Use spaces instead of tabs set smarttab " Smart tab behavior

Essential Settings Reference

Setting What It Does
set number / set nu Show line numbers
set nonumber / set nonu Hide line numbers
set autoindent / set ai Auto-indent new lines
set tabstop=4 / set ts=4 Tab width = 4 spaces
set shiftwidth=4 / set sw=4 Indent width = 4 spaces
set expandtab / set et Use spaces instead of tabs
set ignorecase / set ic Case-insensitive search
set smartcase / set scs Case-sensitive if caps in search
set hlsearch / set hls Highlight search results
set incsearch / set is Show matches while typing
set showmatch / set sm Highlight matching brackets
set ruler Show line/column in status
set wrap Wrap long lines
set nowrap Don't wrap long lines
# View current setting :set number? # Toggle setting :set number! # View all settings :set all # View only changed settings :set

Abbreviations

Abbreviations automatically expand short text into longer strings.

Defining Abbreviations

:ab teh the # Fix typo :ab myemail user@example.com :ab todo TODO(username): :ab dts `date +%Y-%m-%d`

In .exrc File

" Common typos ab teh the ab recieve receive ab seperate separate " Email and signatures ab myemail john.doe@company.com ab myname John Doe " Code snippets ab pyhead #!/usr/bin/env python3 ab shhead #!/bin/bash ab todo TODO(jdoe): ab fixme FIXME(jdoe): " Templates ab ifmain if __name__ == '__main__': ab forloop for i in range():

Managing Abbreviations

:ab # List all abbreviations :ab myemail # Show specific abbreviation :una myemail # Remove abbreviation :abc # Clear all abbreviations
Note: Abbreviations only expand when you type a non-word character (space, punctuation) after them.
TRY IT NOW: Add :ab myname Your Name to your session. Type "myname " (with space) in insert mode and watch it expand.

Key Mapping

Mappings let you create custom keybindings and shortcuts.

Basic Mapping

:map key sequence # Map in command mode :map! key sequence # Map in insert mode :imap key sequence # Insert mode (vim) :nmap key sequence # Normal mode (vim) :vmap key sequence # Visual mode (vim)

Useful Mappings

" Function keys map #1 :w^M " F1 = save (^M is Enter) map #2 :wq^M " F2 = save and quit map #3 :q!^M " F3 = quit without save " Leader key mappings (vim, requires 'let mapleader') let mapleader = "," map <leader>w :w<CR> " ,w = save map <leader>q :q<CR> " ,q = quit map <leader>n :set number!<CR> " ,n = toggle numbers " Quick edits map ,v :e ~/.vimrc<CR> " ,v = edit vimrc map ,s :source ~/.vimrc<CR> " ,s = reload vimrc " Navigation map <Space< <964C-f> " Space = page down map <C-n> :n<CR> " Ctrl+n = next file map <C-p> :prev<CR> " Ctrl+p = previous file " Insert mode mappings imap jj <Esc> " jj = escape (vim) imap <C-d> <C-r>=strftime("%Y-%m-%d")<CR> " Ctrl+d = date " Comment toggling map ,c :s/^/# /<CR> " ,c = comment line map ,u :s/^# //<CR> " ,u = uncomment line " Search map <leader>h :noh<CR> " ,h = clear search highlight

Special Key Notations (VIM)

Notation Key
<CR> Enter/Return
<Esc> Escape
<Space> Space bar
<Tab> Tab
<C-x> Ctrl+x
<S-x> Shift+x
<A-x> or <M-x> Alt+x
<F1>-<F12> Function keys
<leader> Leader key (configurable)

Viewing and Removing Maps

:map # List all mappings :map key # Show mapping for key :unmap key # Remove mapping :mapclear # Clear all mappings :imap # List insert mode mappings :iunmap key # Remove insert mapping
PRACTICAL EXAMPLE: Development Mappings
" Python development map ,r :!python %<CR> " ,r = run current file map ,t :!pytest %<CR> " ,t = test current file map ,p oimport pdb; pdb.set_trace()<Esc> " ,p = add breakpoint " Quick commenting vmap ,c :s/^/# /<CR> " Visual: ,c = comment vmap ,u :s/^# //<CR> " Visual: ,u = uncomment " File operations map ,w :w<CR> " ,w = save map ,x :x<CR> " ,x = save and quit map ,e :e " Format code map ,f gg=G`` " ,f = format entire file
TRY IT NOW (VIM): Add :map ,w :w<CR> then try pressing ,w to save.

Advanced .vimrc Configuration

For vim users, here's a comprehensive .vimrc to use as a starting point:

" ==================== " Basic Settings " ==================== set nocompatible " Use vim features syntax on " Syntax highlighting filetype plugin indent on " File type detection " Display set number " Line numbers set relativenumber " Relative line numbers set ruler " Show cursor position set showcmd " Show partial commands set showmode " Show current mode set laststatus=2 " Always show status line set cursorline " Highlight current line set wildmenu " Command completion menu set scrolloff=5 " Lines to keep visible set colorcolumn=80 " Highlight column 80 " Search set hlsearch " Highlight search results set incsearch " Incremental search set ignorecase " Case-insensitive search set smartcase " Smart case sensitivity " Editing set autoindent " Auto-indent set smartindent " Smart indent set expandtab " Spaces instead of tabs set tabstop=4 " Tab = 4 spaces set shiftwidth=4 " Indent = 4 spaces set softtabstop=4 " Backspace deletes 4 spaces set backspace=indent,eol,start " Allow backspace set showmatch " Show matching brackets set matchtime=2 " Bracket match time " Files set autowrite " Auto-save set autoread " Auto-reload changed files set backup " Keep backups set backupdir=~/.vim/backup// " Backup directory set directory=~/.vim/swap// " Swap directory set undofile " Persistent undo set undodir=~/.vim/undo// " Undo directory " Performance set lazyredraw " Don't redraw during macros set updatetime=300 " Faster updates " ==================== " Key Mappings " ==================== let mapleader = "," " Save and quit nnoremap <leader>w :w<CR> nnoremap <leader>q :q<CR> nnoremap <leader>x :x<CR> " Navigation nnoremap <C-h> <C-w>h nnoremap <C-j> <C-w>j nnoremap <C-K><C-w>k nnoremap <C-l> <C-w>l " Clear search highlight nnoremap <leader>h :noh<CR> " Toggle options nnoremap <leader>n :set number!<CR> nnoremap <leader>r :set relativenumber!<CR> nnoremap <leader>p :set paste!<CR> " Quick edit vimrc nnoremap <leader>ev :e $MYVIMRC<CR> nnoremap <leader>sv :source $MYVIMRC<CR> " Comment toggle (adjust for file type) nnoremap <leader>c :s/^/# /<CR>:noh<CR> nnoremap <leader>u :s/^# //<CR>:noh<CR> vnoremap <leader>c :s/^/# /<CR>:noh<CR> vnoremap <leader>u :s/^# //<CR>:noh<CR> " ==================== " Abbreviations " ==================== iab pyhead #!/usr/bin/env python3 iab shhead #!/bin/bash iab @@ your.email@example.com " ==================== " Auto Commands " ==================== " Remove trailing whitespace on save autocmd BufWritePre * :%s/\s\+$//e " Return to last edit position autocmd BufReadPost * \ if line("'\"") > 0 && line("'\"") <= line("$") | \ exe "normal! g`\"" | \ endif " File type specific settings autocmd FileType python setlocal ts=4 sw=4 et autocmd FileType javascript setlocal ts=2 sw=2 et autocmd FileType html setlocal ts=2 sw=2 et autocmd FileType yaml setlocal ts=2 sw=2 et " ==================== " Status Line " ==================== set statusline=%f " Filename set statusline+=%m " Modified flag set statusline+=%r " Readonly flag set statusline+=%= " Right align set statusline+=%y " File type set statusline+=\ %l/%L " Line/total set statusline+=\ %c " Column set statusline+=\ %P " Percentage " ==================== " Colors " ==================== set background=dark " colorscheme desert " Uncomment if available
Note: Create necessary directories:
mkdir -p ~/.vim/backup ~/.vim/swap ~/.vim/undo

Advanced Editing Techniques

Working with Paragraphs

{ # Jump to previous paragraph } # Jump to next paragraph dap # Delete around paragraph yap # Yank around paragraph gq} # Format to next paragraph gqap # Format paragraph " Format text to width :set textwidth=80 gqG # Format from cursor to end

Case Conversion

~ # Toggle case of character g~w # Toggle case of word gUw # Uppercase word guw # Lowercase word gUU # Uppercase line guu # Lowercase line # In visual mode U # Uppercase selection u # Lowercase selection ~ # Toggle case of selection

Increment/Decrement Numbers

Ctrl+a # Increment number under cursor Ctrl+x # Decrement number under cursor 10 Ctrl+a # Increment by 10 # Visual block increment (vim) Ctrl+v # Visual block mode select numbers g Ctrl+a # Increment sequentially (1,2,3...)

Digraphs (Special Characters)

# In insert mode: Ctrl+k char1 char2 # Insert digraph # Common digraphs: Ctrl+k << : « Ctrl+k >> : » Ctrl+k 12 : ½ Ctrl+k 14 : ¼ Ctrl+k (c : © Ctrl+k Rg : ® :digraphs # List all digraphs

Session Management (VIM)

# Save session :mksession ~/my-session.vim :mksession! ~/my-session.vim " Overwrite existing # Load session :source ~/my-session.vim # Or from command line: vim -S ~/my-session.vim # What's saved in session: " - Window layout " - Working directory " - File buffers " - Cursor positions " - Marks
Add to .vimrc for auto-session:
" Auto-save session on quit autocmd VimLeave * mksession! ~/.vim/session.vim " Load last session nnoremap <leader>ss :source ~/.vim/session.vim<CR>

Integration with Development Tools

Running External Commands

:!command # Run shell command :.!command # Filter current line through command :%!command # Filter entire file through command :5,10!command # Filter lines 5-10 # Examples: :!make # Run make :!git status # Git status :.!date # Replace line with date :%!python # Execute file as Python :5,10!sort # Sort lines 5-10

Reading Command Output

:r !ls -la # Insert directory listing :r !date # Insert current date :r !git log -5 # Insert recent commits :r !grep -r pattern * # Insert search results

Vim with Make

:make # Run make :cn # Next error :cp # Previous error :cl # List errors :cc # Show current error :copen # Open quickfix window :cclose # Close quickfix window

Vim with Grep

:grep pattern files # Run grep :cn # Next match :cp # Previous match :copen # Open results # Example: :grep -r "TODO" *.py :copen

Power User Workflows

WORKFLOW 1: Code Review Preparation
# Extract all TODO comments :g/TODO/y A # Create review file :e review.txt "ap # Add line numbers and format :%!nl :%s/$/ [ ]/ # Result: 1 TODO: Fix authentication [ ] 2 TODO: Add error handling [ ] 3 TODO: Update documentation [ ]
WORKFLOW 2: Config File Templating
# Read template :r ~/.templates/nginx.conf # Use macro to customize qa /SERVER_NAME cw ESC /PORT cw ESC j q # Apply to multiple blocks @a @a @a
WORKFLOW 3: Database Result Formatting
# Paste raw SQL output :r !mysql -e "SELECT * FROM users" # Format as table :%!column -t # Convert to CSV :%s/\s\+/,/g # Or convert to JSON (with jq) :%!jq -R 'split(",") | {id: .[0], name: .[1], email: .[2]}'
WORKFLOW 4: Batch File Generation
# Create list of files to generate :e filelist.txt file1 file2 file3 # Record macro to create files qa yy :e <C-r>".py<CR> idef main(): pass if __name__ == '__main__': main() <Esc> :wq<CR> q # Apply to all lines :e filelist.txt @a @a @a

Troubleshooting and Recovery

Recovering from Swap Files

# If you see swap file warning: :recover " Recover the file :e " Reload :q! " Quit without saving # List swap files :sw # Delete swap file after recovery :!rm .filename.swp

Dealing with Locked Files

:e! filename " Force edit :w !sudo tee % " Save with sudo :set noreadonly " Remove readonly flag

Fixing Common Issues

# Terminal messed up after Ctrl+Z :shell fg reset # Undo tree corrupted :earlier 1h " Go back 1 hour :later 30m " Go forward 30 minutes # File encoding issues :set fileencoding=utf-8 :w

Performance Tips

Optimization Techniques:
# Profile vim startup vim --startuptime startup.log cat startup.log # Identify slow plugins # Disable one at a time and test # Speed up large files :syntax off :set nowrap :set norelativenumber

What's Next?

Congratulations! You've mastered advanced VI techniques. You now know:

The next tutorial covers power user secrets, efficiency tricks, and advanced VI techniques that make you unstoppable.

Created for Linux System Administrators | Part 4 of the VI Learning Series

Your VI environment is now a powerful development tool!

← Back to VI Index ↑ Back to EXPANDED