Vim Essentials
1. Why Vim Matters
vi is on EVERY Unix system. In rescue mode, recovery environments, minimal containers, embedded systems - vim is there when nothing else is. This isn’t about editor preferences; it’s about having a tool that works when SSH is your only option.
|
Learning vim is a survival skill, not a lifestyle choice. You will encounter systems where:
|
2. Understanding Modal Editing
2.1. The Modal Architecture
╔══════════════════════════════════════════════════════════════════════════════╗
║ VIM MODAL ARCHITECTURE ║
╠══════════════════════════════════════════════════════════════════════════════╣
║ ║
║ ┌─────────────────────────────────────────────────────────────────────┐ ║
║ │ NORMAL MODE (Default) │ ║
║ │ Navigation • Commands • Text Objects • Operators │ ║
║ │ │ ║
║ │ Press: Esc (from any mode) or Ctrl+[ or Ctrl+C │ ║
║ └─────────────────────────────────────────────────────────────────────┘ ║
║ │ │ │ │ ║
║ │ i,a,o,I,A,O │ v,V,Ctrl-v │ : │ /,? ║
║ ▼ ▼ ▼ ▼ ║
║ ┌────────────┐ ┌────────────┐ ┌────────────┐ ┌────────────┐ ║
║ │ INSERT │ │ VISUAL │ │ COMMAND │ │ SEARCH │ ║
║ │ │ │ │ │ LINE │ │ │ ║
║ │ Type text │ │ Select │ │ Ex cmds │ │ /pattern │ ║
║ │ │ │ regions │ │ :command │ │ ?pattern │ ║
║ └────────────┘ └────────────┘ └────────────┘ └────────────┘ ║
║ ║
║ OPERATOR + MOTION = ACTION ║
║ d + w = delete word ║
║ c + i" = change inside quotes ║
║ y + ap = yank around paragraph ║
║ ║
╚══════════════════════════════════════════════════════════════════════════════╝
2.2. Why Modal?
The power of modal editing:
| Modeless Editor | Vim (Modal) | Advantage |
|---|---|---|
Ctrl+Shift+Arrow to select word |
|
3 keys vs 4, no modifier gymnastics |
Click, drag, Ctrl+C, click, Ctrl+V |
|
Works without mouse, faster |
Find & Replace dialog, regex checkbox, options… |
|
Inline, immediate, scriptable |
Home, Shift+End, Delete |
|
Composable: operators + motions |
2.3. The Grammar of Vim
Vim commands follow a consistent grammar:
[count] operator [count] motion/text-object
Examples:
3dw = delete 3 words
d3w = delete 3 words (equivalent)
2y3j = yank 2 times (3 lines down) = 6 lines total
ci" = change inside double quotes
da( = delete around parentheses (including parens)
3. Survival Commands
If you remember nothing else, these will save you:
i Enter insert mode (start typing)
Esc Return to normal mode (CRITICAL)
:wq Save and quit
:q! Quit without saving (abandon ALL changes)
:w Save only (don't quit)
u Undo last change
Ctrl+r Redo
|
Esc is your panic button. If something feels wrong, press Esc repeatedly until you’re back in normal mode. Then assess. |
4. Opening and Creating Files
4.1. Basic Opening
# Open existing file
vim /etc/ssh/sshd_config
# Open at specific line number
vim +25 /etc/ssh/sshd_config
# Open at first occurrence of pattern
vim +/PasswordAuthentication /etc/ssh/sshd_config
# Open at last line
vim + /var/log/syslog
# Open read-only (can't accidentally save)
vim -R /etc/passwd
view /etc/passwd # alias for vim -R
# Open multiple files
vim file1.conf file2.conf file3.conf
# Open in diff mode
vim -d file1.conf file2.conf
vimdiff file1.conf file2.conf # alias
# Open in binary mode (for hex editing with xxd)
vim -b /path/to/binary
5. Exit Strategies
| Command | Action | When to Use |
|---|---|---|
|
Write (save) only |
Checkpoint without quitting |
|
Quit (fails if unsaved changes) |
Exit after saving |
|
Write and quit |
Normal exit with save |
|
Write and quit (only if changed) |
Like :wq but doesn’t update timestamp if unchanged |
|
Write and quit (normal mode) |
Fast exit, no colon needed |
|
Quit without saving |
Abandon all changes |
|
Quit without saving (normal mode) |
Fast abandon |
|
Quit all windows |
Exit vim with multiple windows |
|
Quit all without saving |
Abandon all windows |
|
Write and quit all |
Save all open files and exit |
|
Quit with error code |
Signal failure to calling process (scripts) |
6. Insert Mode Entry Points
Understanding WHERE your cursor goes when entering insert mode:
╔════════════════════════════════════════════════════════════════════════════╗
║ Line: "The quick brown fox jumps over the lazy dog" ║
║ ▲ ║
║ cursor ║
╠════════════════════════════════════════════════════════════════════════════╣
║ i = insert BEFORE cursor → "The quick bro|wn fox..." ║
║ a = append AFTER cursor → "The quick brow|n fox..." ║
║ I = insert at line BEGINNING → "|The quick brown fox..." ║
║ A = append at line END → "...lazy dog|" ║
║ o = open line BELOW → new line below, insert mode ║
║ O = open line ABOVE → new line above, insert mode ║
║ s = substitute char (delete + insert) → "The quick bro|n fox..." ║
║ S = substitute line (delete line + insert) → "|" (whole line cleared) ║
║ C = change to EOL → "The quick bro|" (rest deleted) ║
╚════════════════════════════════════════════════════════════════════════════╝
6.1. Insert Mode Commands
While in insert mode, you have limited commands:
| Key | Action |
|---|---|
|
Delete character before cursor (backspace) |
|
Delete word before cursor |
|
Delete to beginning of line |
|
Indent current line |
|
Unindent current line |
|
Autocomplete (next match) |
|
Autocomplete (previous match) |
|
Insert contents of register |
|
Execute ONE normal mode command, return to insert |
|
Escape (same as Esc key) |
# In insert mode, paste from clipboard register:
Ctrl+r +
# Paste from yank register:
Ctrl+r 0
# Paste from named register 'a':
Ctrl+r a
7. Navigation Mastery
7.1. Character and Word Movement
╔═══════════════════════════════════════════════════════════════════════════╗
║ BASIC MOVEMENT (NORMAL MODE) ║
╠═══════════════════════════════════════════════════════════════════════════╣
║ ║
║ CHARACTER: h ← · → l (also: ← ↓ ↑ → arrow keys, but slower) ║
║ j ↓ ║
║ k ↑ ║
║ ║
║ WORD: w → next word start ║
║ W → next WORD start (whitespace-delimited) ║
║ e → end of word ║
║ E → end of WORD ║
║ b ← previous word start ║
║ B ← previous WORD start ║
║ ge ← end of previous word ║
║ ║
║ LINE: 0 → beginning of line (column 0) ║
║ ^ → first non-blank character ║
║ $ → end of line ║
║ g_ → last non-blank character ║
║ ║
╚═══════════════════════════════════════════════════════════════════════════╝
|
word vs WORD:
Example line:
|
7.2. Screen and File Movement
╔═══════════════════════════════════════════════════════════════════════════╗
║ SCREEN NAVIGATION ║
╠═══════════════════════════════════════════════════════════════════════════╣
║ ║
║ FILE POSITION: ║
║ gg → first line of file ║
║ G → last line of file ║
║ {n}G → go to line n (e.g., 50G = line 50) ║
║ :{n} → go to line n (e.g., :50) ║
║ {n}% → go to n% through file (50% = middle) ║
║ ║
║ SCREEN POSITION: ║
║ H → top of screen (High) ║
║ M → middle of screen (Middle) ║
║ L → bottom of screen (Low) ║
║ ║
║ SCROLLING: ║
║ Ctrl+f → forward one screen (page down) ║
║ Ctrl+b → backward one screen (page up) ║
║ Ctrl+d → down half screen ║
║ Ctrl+u → up half screen ║
║ Ctrl+e → scroll down one line (cursor stays) ║
║ Ctrl+y → scroll up one line (cursor stays) ║
║ ║
║ CURSOR CENTERING: ║
║ zz → center cursor line on screen ║
║ zt → cursor line to top of screen ║
║ zb → cursor line to bottom of screen ║
║ ║
╚═══════════════════════════════════════════════════════════════════════════╝
7.3. Jump Motions
╔═══════════════════════════════════════════════════════════════════════════╗
║ JUMP MOTIONS ║
╠═══════════════════════════════════════════════════════════════════════════╣
║ ║
║ PARAGRAPH: ║
║ { → previous blank line (paragraph start) ║
║ } → next blank line (paragraph end) ║
║ ║
║ SENTENCE: ║
║ ( → previous sentence ║
║ ) → next sentence ║
║ ║
║ SECTION (for code): ║
║ [[ → previous section/function ║
║ ]] → next section/function ║
║ ║
║ MATCHING: ║
║ % → matching bracket/paren/brace ║
║ ║
║ JUMPS (Ctrl+o / Ctrl+i): ║
║ Ctrl+o → jump back (older position) ║
║ Ctrl+i → jump forward (newer position) ║
║ :jumps → show jump list ║
║ ║
║ CHANGES: ║
║ g; → go to previous change location ║
║ g, → go to next change location ║
║ :changes → show change list ║
║ ║
╚═══════════════════════════════════════════════════════════════════════════╝
7.4. Find Motions (Within Line)
╔═══════════════════════════════════════════════════════════════════════════╗
║ FIND WITHIN LINE ║
╠═══════════════════════════════════════════════════════════════════════════╣
║ ║
║ Line: "The quick brown fox jumps over the lazy dog" ║
║ ▲ ║
║ cursor ║
║ ║
║ f{char} → find char forward (cursor ON char) ║
║ F{char} → find char backward (cursor ON char) ║
║ t{char} → til char forward (cursor BEFORE char) ║
║ T{char} → til char backward (cursor AFTER char) ║
║ ; → repeat last f/F/t/T forward ║
║ , → repeat last f/F/t/T backward ║
║ ║
║ Examples (cursor at T): ║
║ fo → "The quick brown f|ox..." (on 'o' of fox) ║
║ to → "The quick brown |fox..." (before 'o' of fox) ║
║ 2fo → "The quick brown fox jumps |over..." (2nd 'o') ║
║ ║
║ POWERFUL WITH OPERATORS: ║
║ dt) → delete til closing paren ║
║ cf" → change through next double quote ║
║ yf, → yank through comma ║
║ ║
╚═══════════════════════════════════════════════════════════════════════════╝
8. Operators and Text Objects
8.1. Core Operators
| Operator | Action | Example |
|---|---|---|
|
Delete (cut) |
|
|
Change (delete + enter insert) |
|
|
Yank (copy) |
|
|
Indent right |
|
|
Indent left |
|
|
Auto-indent |
|
|
Lowercase |
|
|
Uppercase |
|
|
Toggle case |
|
|
Filter through external command |
|
8.2. Text Objects
Text objects define regions of text. Use with operators: {operator}\{a|i\}{object}
-
a= "around" (includes delimiters/whitespace) -
i= "inside" (excludes delimiters)
╔═══════════════════════════════════════════════════════════════════════════╗
║ TEXT OBJECTS ║
╠═══════════════════════════════════════════════════════════════════════════╣
║ ║
║ PAIRED DELIMITERS: ║
║ i" / a" → inside/around double quotes ║
║ i' / a' → inside/around single quotes ║
║ i` / a` → inside/around backticks ║
║ i( / a( → inside/around parentheses (also ib/ab for "block") ║
║ i[ / a[ → inside/around brackets ║
║ i{ / a{ → inside/around braces (also iB/aB for "Block") ║
║ i< / a< → inside/around angle brackets ║
║ it / at → inside/around XML/HTML tags ║
║ ║
║ LANGUAGE UNITS: ║
║ iw / aw → inside/around word ║
║ iW / aW → inside/around WORD (whitespace-delimited) ║
║ is / as → inside/around sentence ║
║ ip / ap → inside/around paragraph ║
║ ║
╚═══════════════════════════════════════════════════════════════════════════╝
8.3. Text Object Examples
Original: func("hello, world", 42)
▲
cursor
ci" → func("|", 42) # Change inside quotes
ca" → func(|, 42) # Change around quotes (includes quotes)
di( → func(|) # Delete inside parens
da( → func| # Delete around parens (includes parens)
Original: <div class="container">content</div>
▲
cursor
cit → <div class="container">|</div> # Change inside tag
dat → | # Delete around tag (whole element)
8.4. Powerful Combinations
# Delete word under cursor
diw
# Change quoted string
ci"
# Delete function arguments
di(
# Yank paragraph
yap
# Sort lines in paragraph
!ipsort
# Lowercase word
guiw
# Delete to next closing brace (for code blocks)
d]}
# Change everything inside current braces
ci{
# Delete HTML tag content
dit
# Reindent entire file
gg=G
9. Registers (Clipboard System)
Vim has multiple "clipboards" called registers.
9.1. Register Types
╔═══════════════════════════════════════════════════════════════════════════╗
║ REGISTERS ║
╠═══════════════════════════════════════════════════════════════════════════╣
║ ║
║ UNNAMED: "" (default for d, c, y) ║
║ NUMBERED: "0 (last yank) ║
║ "1-"9 (last 9 deletes, newest = "1) ║
║ NAMED: "a-"z (you control these) ║
║ "A-"Z (APPEND to named register) ║
║ READ-ONLY: ║
║ ". (last inserted text) ║
║ "% (current filename) ║
║ "# (alternate filename) ║
║ ": (last command) ║
║ EXPRESSION: "= (evaluate expression) ║
║ CLIPBOARD: "+ (system clipboard - X11/Wayland) ║
║ "* (X11 primary selection / middle-click) ║
║ BLACK HOLE: "_ (delete without affecting registers) ║
║ LAST SEARCH: "/ (last search pattern) ║
║ ║
╚═══════════════════════════════════════════════════════════════════════════╝
9.2. Using Registers
" Yank to named register 'a'
"ayy
" Paste from named register 'a'
"ap
" APPEND to register 'a' (note uppercase)
"Ayy
" Yank to system clipboard
"+yy
" Paste from system clipboard
"+p
" Delete without affecting registers (black hole)
"_dd
" View all registers
:registers
:reg
" View specific register
:reg a
" In insert mode, paste from register
Ctrl+r a
" In command line, paste from register
Ctrl+r a
9.3. Register Workflow Example
# Copy several different things for later use:
"ayy # yank line to register 'a'
"byy # yank line to register 'b'
"cyip # yank paragraph to register 'c'
# Now paste them wherever needed:
"ap # paste from 'a'
"bp # paste from 'b'
"cp # paste from 'c'
# They stay in registers until overwritten
10. Marks (Bookmarks)
10.1. Mark Types
| Mark | Scope | Example |
|---|---|---|
|
Local to buffer |
|
|
Global (across files) |
|
|
Last positions in files (auto, .viminfo) |
|
|
Position before last jump |
|
|
Last change |
|
|
Last insert |
|
|
Start/end of last yank/change |
|
|
Start/end of last visual selection |
|
10.2. Working with Marks
" Set mark 'a' at current position
ma
" Jump to line containing mark 'a'
'a
" Jump to exact position of mark 'a' (line and column)
`a
" Jump to mark, show that line at center of screen
'azz
" Delete from current line to mark 'a'
d'a
" Yank from current position to mark 'a'
y`a
" List all marks
:marks
" Delete mark 'a'
:delmarks a
" Delete all lowercase marks
:delmarks!
" Jump between last two positions (toggle)
''
" Jump back to position before last jump
Ctrl+o
11. Macros
Macros record and replay keystrokes.
11.1. Recording and Playing
╔═══════════════════════════════════════════════════════════════════════════╗
║ MACROS ║
╠═══════════════════════════════════════════════════════════════════════════╣
║ ║
║ RECORD: ║
║ q{register} → start recording to register (e.g., qa) ║
║ ... keystrokes ... ║
║ q → stop recording ║
║ ║
║ PLAY: ║
║ @{register} → play macro (e.g., @a) ║
║ @@ → replay last macro ║
║ {n}@{register} → play macro n times (e.g., 10@a) ║
║ ║
║ VIEW: ║
║ :reg {reg} → see macro contents (it's just text in register) ║
║ ║
║ EDIT: ║
║ "ap → paste macro as text ║
║ ... edit ... ║
║ "ay$ → yank back to register ║
║ ║
╚═══════════════════════════════════════════════════════════════════════════╝
11.2. Macro Best Practices
# Start from a consistent position (beginning of line, etc.)
0
# Use motions that work regardless of line length
$ (end), 0 (start), w (word), f{char} (find)
# End in a position ready for the next iteration
j0 (next line, beginning)
# Make the macro FAIL on last iteration to stop naturally
# (e.g., search that won't match, j at last line)
12. Search and Replace
12.1. Basic Search
" Search forward
/pattern
" Search backward
?pattern
" Next match
n
" Previous match
N
" Search word under cursor (forward)
*
" Search word under cursor (backward)
#
" Search partial word under cursor
g*
g#
" Clear search highlighting
:noh
:nohlsearch
12.2. Search Options
" Case insensitive search
/pattern\c
" Case sensitive search (override ignorecase setting)
/pattern\C
" Very magic mode (most special chars don't need escaping)
/\vpattern
" Very nomagic mode (all special chars are literal)
/\Vpattern
" Word boundary
/\<word\>
12.3. Substitute (Search & Replace)
" Current line, first occurrence
:s/old/new/
" Current line, all occurrences
:s/old/new/g
" Entire file, all occurrences
:%s/old/new/g
" Entire file, with confirmation
:%s/old/new/gc
" Line range (lines 5-10)
:5,10s/old/new/g
" From current line to end
:.,$s/old/new/g
" From current line to mark 'a'
:.,'as/old/new/g
" Lines matching pattern
:g/pattern/s/old/new/g
" Case insensitive
:%s/old/new/gi
12.4. Substitute Special Patterns
" & = matched pattern
:%s/error/[&]/g " error → [error]
" \0 = entire match, \1-\9 = capture groups
:%s/\(\w\+\)=\(\w\+\)/\2=\1/g " swap foo=bar to bar=foo
" \r = newline in replacement
:%s/,/\r/g " Replace commas with newlines
" \n = newline in search pattern
:%s/\n\n/\r/g " Collapse double newlines
" ~ = previous replacement string
:%s/foo/bar/g " First replacement
:%s/baz/~/g " baz → bar (reuse last replacement)
" \u, \l = uppercase/lowercase next char
:%s/\<\(\w\)/\u\1/g " Capitalize first letter of words
" \U, \L = uppercase/lowercase until \E
:%s/.*/\U&/g " Entire line uppercase
12.5. Global Command
The :g command executes commands on matching lines:
" Delete lines containing pattern
:g/pattern/d
" Delete lines NOT containing pattern
:g!/pattern/d
:v/pattern/d
" Move matching lines to end of file
:g/pattern/m$
" Copy matching lines to register 'a'
:g/pattern/y A
" Execute normal mode commands on matching lines
:g/pattern/normal @a
" Reverse all lines
:g/^/m0
" Number lines containing pattern
:let i=1 | g/pattern/s/^/\=i.': '/ | let i+=1
13. Visual Mode Deep Dive
13.1. Visual Selection Types
╔═══════════════════════════════════════════════════════════════════════════╗
║ VISUAL MODES ║
╠═══════════════════════════════════════════════════════════════════════════╣
║ ║
║ v Character-wise: Select characters ║
║ ║
║ The quick [brown fox] jumps ║
║ ▲─────────▲ selected ║
║ ║
║ V Line-wise: Select entire lines ║
║ ║
║ [The quick brown fox jumps ] ║
║ [over the lazy dog. ] ║
║ entire lines selected ║
║ ║
║ Ctrl+v Block-wise: Select rectangle/column ║
║ ║
║ The [qui]ck brown fox jumps ║
║ ove [the] lazy dog. ║
║ And [the]y lived happily ║
║ ▲───▲ rectangular block ║
║ ║
║ gv Reselect last visual selection ║
║ o Move to other end of selection ║
║ ║
╚═══════════════════════════════════════════════════════════════════════════╝
13.2. Visual Mode Operations
" After selecting with v, V, or Ctrl+v:
d " Delete selection
y " Yank selection
c " Change selection (delete + insert)
> " Indent right
< " Indent left
= " Auto-indent
u " Lowercase
U " Uppercase
~ " Toggle case
J " Join lines
: " Enter command mode for selection (shows :'<,'>)
!cmd " Filter through external command
r{char} " Replace all selected characters with {char}
13.3. Block Visual Power Moves
# Add prefix to multiple lines:
Ctrl+v " Start block visual
jjj " Select down
I " Insert at beginning of block
# prefix " Type what you want
Esc " Apply to all lines
# Add suffix to multiple lines:
Ctrl+v " Start block visual
jjj " Select down
$ " Extend to end of lines
A " Append after block
# suffix " Type what you want
Esc " Apply to all lines
# Replace column:
Ctrl+v " Start block visual
jjj " Select down
lll " Select right
c " Change
newtext " Type replacement
Esc " Apply
14. Windows, Buffers, and Tabs
14.1. Understanding the Hierarchy
╔═══════════════════════════════════════════════════════════════════════════╗
║ VIM WINDOW HIERARCHY ║
╠═══════════════════════════════════════════════════════════════════════════╣
║ ║
║ BUFFER: A file loaded into memory ║
║ - Can be visible in 0, 1, or many windows ║
║ - :ls lists all buffers ║
║ ║
║ WINDOW: A viewport onto a buffer ║
║ - Multiple windows can show same buffer ║
║ - Split with :split (horizontal) or :vsplit (vertical) ║
║ ║
║ TAB: A collection of windows ║
║ - Like workspaces/virtual desktops ║
║ - Each tab has its own window layout ║
║ ║
║ ┌────────────────── TAB 1 ──────────────────┐ ┌─── TAB 2 ───┐ ║
║ │ ┌─ WINDOW ─┐ ┌─ WINDOW ─┐ │ │ │ ║
║ │ │ Buffer A │ │ Buffer B │ │ │ Buffer C │ ║
║ │ └──────────┘ └──────────┘ │ │ │ ║
║ │ ┌────────── WINDOW ──────────┐ │ │ │ ║
║ │ │ Buffer A │ (same!) │ │ │ ║
║ │ └────────────────────────────┘ │ │ │ ║
║ └───────────────────────────────────────────┘ └─────────────┘ ║
║ ║
╚═══════════════════════════════════════════════════════════════════════════╝
14.2. Buffer Commands
" List buffers
:ls
:buffers
" Switch buffers
:b {name} " By name (partial match)
:b {n} " By number
:bn " Next buffer
:bp " Previous buffer
:bf " First buffer
:bl " Last buffer
Ctrl+^ " Alternate buffer (last edited)
" Open file in new buffer
:e filename
" Close buffer
:bd " Delete (close) current buffer
:bd {n} " Delete buffer n
:bd! " Force close (discard changes)
:bw " Wipe (more aggressive than bd)
" Buffer status indicators in :ls
% " Current buffer in current window
# " Alternate buffer (Ctrl+^)
a " Active (loaded and visible)
h " Hidden (loaded but not visible)
+ " Modified
14.3. Window Commands
" Split windows
:split [file] " Horizontal split
:sp [file]
:vsplit [file] " Vertical split
:vs [file]
:new " New horizontal window with empty buffer
:vnew " New vertical window with empty buffer
" Navigate windows
Ctrl+w w " Cycle through windows
Ctrl+w h/j/k/l " Move to window left/down/up/right
Ctrl+w H/J/K/L " MOVE window to left/bottom/top/right
Ctrl+w p " Previous window
Ctrl+w t " Top-left window
Ctrl+w b " Bottom-right window
" Resize windows
Ctrl+w = " Equal size all windows
Ctrl+w _ " Maximize height
Ctrl+w | " Maximize width
Ctrl+w + " Increase height
Ctrl+w - " Decrease height
Ctrl+w > " Increase width
Ctrl+w < " Decrease width
:resize {n} " Set height to n
:vertical resize {n} " Set width to n
" Close windows
Ctrl+w q " Quit window
Ctrl+w c " Close window
Ctrl+w o " Close all OTHER windows (only this one)
:only " Same as Ctrl+w o
" Rotate windows
Ctrl+w r " Rotate windows downward
Ctrl+w R " Rotate windows upward
Ctrl+w x " Exchange with next window
14.4. Tab Commands
" Create tabs
:tabnew [file] " New tab
:tabe [file] " Tab edit
" Navigate tabs
gt " Next tab
gT " Previous tab
{n}gt " Go to tab n
:tabn " Next tab
:tabp " Previous tab
:tabfirst " First tab
:tablast " Last tab
" Manage tabs
:tabclose " Close current tab
:tabc
:tabonly " Close all other tabs
:tabo
:tabmove {n} " Move tab to position n
:tabs " List tabs
" Open all buffers in tabs
:tab ball
" Open all arguments in tabs
vim -p file1 file2 file3
15. Ex Commands (Command-Line Mode)
15.1. File Operations
" Save
:w " Write current file
:w filename " Write to filename
:w! filename " Overwrite (force)
:w >> filename " Append to file
:{range}w filename " Write range to file
" Read
:r filename " Read file, insert below cursor
:r !command " Read command output
" Manage files
:e filename " Edit file
:e! " Revert to saved (discard changes)
:saveas filename " Save as new name
:file newname " Rename buffer (not file on disk)
" View file info
:f " Show filename and position
Ctrl+g " Same as :f
g Ctrl+g " More detailed info (words, bytes)
15.2. Range Specification
" Line specifications
:5 " Line 5
:. " Current line
:$ " Last line
:% " All lines (same as 1,$)
:'a " Line with mark 'a'
:'<,'> " Visual selection (auto-inserted)
:/pattern/ " Next line matching pattern
:?pattern? " Previous line matching pattern
" Ranges
:5,10 " Lines 5 through 10
:.,.+5 " Current line through 5 lines down
:.-3,.+3 " 3 lines above through 3 lines below
:/start/,/end/ " From line matching 'start' to line matching 'end'
" Range examples
:5,10d " Delete lines 5-10
:.,+5y " Yank current line plus 5 more
:%s/foo/bar/g " Replace in entire file
:'<,'>!sort " Sort visual selection
15.3. External Commands
" Run command, show output
:!ls -la
" Run command, insert output below cursor
:r !ls -la
:r !date
:r !curl -s http://example.com
" Filter through command
:{range}!command
" Sort entire file
:%!sort
" Sort and dedupe
:%!sort -u
" Format JSON
:%!jq .
" Filter visual selection
:'<,'>!sort
:'<,'>!uniq
:'<,'>!awk '{print $2}'
" Write to command (useful for sudo)
:w !sudo tee % > /dev/null
16. Neovim Specific Features
16.1. Configuration
Neovim configuration lives in different locations:
# Neovim config directory
~/.config/nvim/
# Main config file (choose ONE)
~/.config/nvim/init.vim # Vimscript
~/.config/nvim/init.lua # Lua (preferred for new configs)
16.2. Lua Configuration Basics
-- ~/.config/nvim/init.lua
-- Set options
vim.opt.number = true
vim.opt.relativenumber = true
vim.opt.tabstop = 4
vim.opt.shiftwidth = 4
vim.opt.expandtab = true
vim.opt.smartindent = true
vim.opt.wrap = false
vim.opt.hlsearch = true
vim.opt.incsearch = true
vim.opt.termguicolors = true
-- Set leader key
vim.g.mapleader = " "
-- Keymaps
vim.keymap.set("n", "<leader>w", ":w<CR>")
vim.keymap.set("n", "<leader>q", ":q<CR>")
vim.keymap.set("n", "<Esc>", ":noh<CR>")
-- Clipboard integration (system clipboard)
vim.opt.clipboard = "unnamedplus"
16.3. Built-in Terminal
" Open terminal in split
:terminal
:term
" Open terminal in vertical split
:vsplit | terminal
" Open terminal in new tab
:tabnew | terminal
" In terminal mode:
Ctrl+\Ctrl+n " Exit to normal mode
i, a, or any insert " Back to terminal mode
" Send keys to terminal
:terminal
i " Enter terminal mode
# run commands...
Ctrl+\Ctrl+n " Back to normal mode
"ap " Paste from register into terminal
16.4. Health Check
" Check neovim health
:checkhealth
" Check specific provider
:checkhealth provider
:checkhealth nvim
16.5. LSP (Language Server Protocol)
-- Basic LSP setup (in init.lua)
-- Requires nvim-lspconfig plugin
local lspconfig = require('lspconfig')
-- Python
lspconfig.pyright.setup{}
-- Bash
lspconfig.bashls.setup{}
-- Go
lspconfig.gopls.setup{}
-- LSP keybindings (add to your config)
vim.keymap.set('n', 'gd', vim.lsp.buf.definition)
vim.keymap.set('n', 'K', vim.lsp.buf.hover)
vim.keymap.set('n', '<leader>rn', vim.lsp.buf.rename)
vim.keymap.set('n', 'gr', vim.lsp.buf.references)
17. Production Scenarios
17.1. Scenario 1: Emergency Config Fix Over SSH
# SSH to server, sshd config broken, locked out
# Connect via console/KVM, fix sshd_config
vi /etc/ssh/sshd_config
# Find PasswordAuthentication line
/PasswordAuthentication
# Change value
cw no Esc
# Or use substitute
:%s/PasswordAuthentication yes/PasswordAuthentication no/g
# Save and quit
:wq
# Restart sshd
# (outside vim)
systemctl restart sshd
17.2. Scenario 2: Bulk Configuration Update
You need to update 50 servers' hostnames in /etc/hosts from old-dc to new-dc:
# Open file
vim /etc/hosts
# Preview change (don't modify yet)
/old-dc
# Make the change
:%s/old-dc\.domain\.local/new-dc.domain.local/gc
# Confirm each (y/n/a/q/l)
# y = yes, n = no, a = all remaining, q = quit, l = last (this one then quit)
# Save
:w
17.3. Scenario 3: Extracting Data from Log File
Extract all IP addresses from auth.log:
vim /var/log/auth.log
# Delete all lines NOT containing IP pattern
:v/\d\{1,3\}\.\d\{1,3\}\.\d\{1,3\}\.\d\{1,3\}/d
# Now file only has lines with IPs
# Extract just the IP (keep only IP, remove rest of line)
:%s/.*\(\d\{1,3\}\.\d\{1,3\}\.\d\{1,3\}\.\d\{1,3\}\).*/\1/
# Sort and dedupe
:%!sort -u
# Save to new file
:w /tmp/unique_ips.txt
17.4. Scenario 4: Multi-File Edit with Argument List
# Open all config files
vim /etc/myapp/*.conf
# See argument list
:args
# Make change in current file
:%s/old_value/new_value/g
# Save and move to next file
:wn
# Or do all at once
:argdo %s/old_value/new_value/g | w
# Or with confirmation
:argdo %s/old_value/new_value/gc | w
17.5. Scenario 5: Diff and Merge Configurations
# Compare two config files
vim -d /etc/nginx/nginx.conf /etc/nginx/nginx.conf.new
# In diff mode:
]c " Jump to next change
[c " Jump to previous change
do " Get change from other window (diff obtain)
dp " Put change to other window (diff put)
:diffupdate " Recalculate diff
:diffoff " Turn off diff mode
# After resolving, save both
:wa
18. Configuration for Sysadmins
18.1. Minimal .vimrc
" ~/.vimrc - Sysadmin essentials
" Basics
set nocompatible " Don't be vi-compatible
set encoding=utf-8 " UTF-8 encoding
" Visual
set number " Line numbers
set ruler " Position in status line
set showcmd " Show partial commands
set showmatch " Highlight matching brackets
syntax on " Syntax highlighting
set background=dark " Dark background
" Search
set hlsearch " Highlight search results
set incsearch " Incremental search
set ignorecase " Case insensitive...
set smartcase " ...unless uppercase used
" Editing
set tabstop=4 " Tab width
set shiftwidth=4 " Indent width
set expandtab " Spaces, not tabs
set autoindent " Auto indent
set backspace=indent,eol,start " Sane backspace
" Files
set nobackup " No backup files
set noswapfile " No swap files (live dangerously)
set autoread " Reload changed files
" Status line
set laststatus=2 " Always show status line
" Convenience mappings
nnoremap <Esc> :noh<CR> " Clear search highlight
nnoremap <leader>w :w<CR> " Quick save
nnoremap <leader>q :q<CR> " Quick quit
" File type specific
autocmd FileType yaml setlocal ts=2 sw=2 expandtab
autocmd FileType sh setlocal ts=4 sw=4 expandtab
autocmd FileType python setlocal ts=4 sw=4 expandtab
18.2. Neovim init.lua Equivalent
-- ~/.config/nvim/init.lua - Sysadmin essentials
-- Basics
vim.opt.encoding = "utf-8"
-- Visual
vim.opt.number = true
vim.opt.ruler = true
vim.opt.showcmd = true
vim.opt.showmatch = true
vim.cmd("syntax on")
vim.opt.background = "dark"
-- Search
vim.opt.hlsearch = true
vim.opt.incsearch = true
vim.opt.ignorecase = true
vim.opt.smartcase = true
-- Editing
vim.opt.tabstop = 4
vim.opt.shiftwidth = 4
vim.opt.expandtab = true
vim.opt.autoindent = true
vim.opt.backspace = "indent,eol,start"
-- Files
vim.opt.backup = false
vim.opt.swapfile = false
vim.opt.autoread = true
-- Status line
vim.opt.laststatus = 2
-- Clipboard (system integration)
vim.opt.clipboard = "unnamedplus"
-- Leader key
vim.g.mapleader = " "
-- Keymaps
vim.keymap.set("n", "<Esc>", ":noh<CR>", { silent = true })
vim.keymap.set("n", "<leader>w", ":w<CR>")
vim.keymap.set("n", "<leader>q", ":q<CR>")
-- File type settings
vim.api.nvim_create_autocmd("FileType", {
pattern = "yaml",
callback = function()
vim.opt_local.tabstop = 2
vim.opt_local.shiftwidth = 2
vim.opt_local.expandtab = true
end
})
19. Quick Reference Card
| Category | Key/Command | Action |
|---|---|---|
Essentials |
||
Exit |
|
Save and quit |
Exit |
|
Quit without saving |
Mode |
|
Return to Normal mode |
Mode |
|
Insert mode |
Movement |
||
Char |
|
Left, down, up, right |
Word |
|
Next word, prev word, end word |
Line |
|
Start, first non-blank, end |
File |
|
Top, bottom |
Search |
|
Find, next, prev |
Editing |
||
Delete |
|
Line, word, to EOL |
Yank |
|
Line, word, to EOL |
Paste |
|
After, before cursor |
Change |
|
Line, word, to EOL |
Undo |
|
Undo, redo |
Text Objects |
||
Inside |
|
Change inside quotes/parens/braces |
Around |
|
Delete around (including delimiters) |
Visual |
||
Select |
|
Char, line, block |
Action |
|
Delete, yank, change selection |
Registers |
||
System |
|
Yank/paste system clipboard |
Named |
|
Yank/paste register 'a' |
Windows |
||
Split |
|
Horizontal, vertical |
Navigate |
|
Move between windows |
Close |
|
Close window |
Search/Replace |
||
Replace |
|
All in file |
Confirm |
|
With confirmation |
Lines |
|
Delete matching lines |