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:

  • nano isn’t installed

  • No GUI is available

  • You’re editing over a 9600 baud serial console

  • The rescue environment has only busybox vi

  • Your only access is through a remote KVM or iLO console

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

viw (visual inside word)

3 keys vs 4, no modifier gymnastics

Click, drag, Ctrl+C, click, Ctrl+V

yap then p (yank around paragraph, paste)

Works without mouse, faster

Find & Replace dialog, regex checkbox, options…​

:%s/old/new/gc

Inline, immediate, scriptable

Home, Shift+End, Delete

d$ (delete to end of line)

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

4.2. Recovery Mode

# Recover from swap file after crash
vim -r /etc/ssh/sshd_config

# List recoverable files
vim -r

# Recover specific swap file
vim -r .sshd_config.swp

4.3. Creating New Files

# Open new file (created on first :w)
vim /etc/myapp/newconfig.conf

# Copy existing file then edit
cp /etc/ssh/sshd_config /etc/ssh/sshd_config.new
vim /etc/ssh/sshd_config.new

5. Exit Strategies

Command Action When to Use

:w

Write (save) only

Checkpoint without quitting

:q

Quit (fails if unsaved changes)

Exit after saving

:wq

Write and quit

Normal exit with save

:x

Write and quit (only if changed)

Like :wq but doesn’t update timestamp if unchanged

ZZ

Write and quit (normal mode)

Fast exit, no colon needed

:q!

Quit without saving

Abandon all changes

ZQ

Quit without saving (normal mode)

Fast abandon

:qa

Quit all windows

Exit vim with multiple windows

:qa!

Quit all without saving

Abandon all windows

:wqa

Write and quit all

Save all open files and exit

:cq

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

Ctrl+h

Delete character before cursor (backspace)

Ctrl+w

Delete word before cursor

Ctrl+u

Delete to beginning of line

Ctrl+t

Indent current line

Ctrl+d

Unindent current line

Ctrl+n

Autocomplete (next match)

Ctrl+p

Autocomplete (previous match)

Ctrl+r {reg}

Insert contents of register

Ctrl+o

Execute ONE normal mode command, return to insert

Ctrl+[

Escape (same as Esc key)

Example: Insert register contents
# 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:

  • word = sequence of letters, digits, underscores (or sequence of other non-blank characters)

  • WORD = sequence of non-blank characters, separated by whitespace

Example line: user@host:/var/log$

  • w stops at: user, @, host, :, /, var, /, log, $

  • W stops at: user@host:/var/log$ (single WORD)

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

d

Delete (cut)

dw delete word

c

Change (delete + enter insert)

cw change word

y

Yank (copy)

yy yank line

>

Indent right

>} indent paragraph

<

Indent left

<ip unindent paragraph

=

Auto-indent

=G fix indent to end of file

gu

Lowercase

guw lowercase word

gU

Uppercase

gUiw uppercase inner word

g~

Toggle case

g~$ toggle case to EOL

!

Filter through external command

!}sort sort paragraph

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

a-z

Local to buffer

ma set, 'a jump

A-Z

Global (across files)

mA set, 'A jump

0-9

Last positions in files (auto, .viminfo)

'0 last file position

'

Position before last jump

'' toggle last two positions

.

Last change

'. go to last edit

^

Last insert

'^ go to last insert

[ / ]

Start/end of last yank/change

'[ start of last change

< / >

Start/end of last visual selection

'< start of last 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

10.3. Global Marks Across Files

" In /etc/ssh/sshd_config, mark important section
mS

" In /etc/pam.d/sshd, mark related section
mP

" Now from anywhere:
'S    " Jump directly to sshd_config at marked line
'P    " Jump directly to pam.d/sshd at marked line

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)

11.3. Practical Macro Example

Task: Comment out lines 10-50 with #

:10                    " Go to line 10
qa                     " Start recording to 'a'
0                      " Beginning of line
i#                     " Insert #
Esc                    " Back to normal
j                      " Next line
q                      " Stop recording

39@a                   " Play 39 more times (10+39=49, so lines 10-50)

11.4. Better: Visual Block for This Task

:10                    " Go to line 10
Ctrl+v                 " Visual block
40j                    " Extend down 40 lines
I                      " Insert mode at block start
#                      " Type the character
Esc                    " Apply to all lines

12. Search and Replace

" 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

17.6. Scenario 6: Edit File Without Write Permission

# Opened as non-root, made changes, can't save
# DO NOT :q! - you'll lose changes!

# Write to sudo
:w !sudo tee % > /dev/null

# You'll be prompted for password
# Then reload the file (or just :q and edit again)
:e!

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

:wq / ZZ

Save and quit

Exit

:q! / ZQ

Quit without saving

Mode

Esc

Return to Normal mode

Mode

i

Insert mode

Movement

Char

h j k l

Left, down, up, right

Word

w b e

Next word, prev word, end word

Line

0 ^ $

Start, first non-blank, end

File

gg G

Top, bottom

Search

/pattern n N

Find, next, prev

Editing

Delete

dd dw d$

Line, word, to EOL

Yank

yy yw y$

Line, word, to EOL

Paste

p P

After, before cursor

Change

cc cw c$

Line, word, to EOL

Undo

u Ctrl+r

Undo, redo

Text Objects

Inside

ci" ci( ci{

Change inside quotes/parens/braces

Around

da" da( da{

Delete around (including delimiters)

Visual

Select

v V Ctrl+v

Char, line, block

Action

d y c

Delete, yank, change selection

Registers

System

"+y "+p

Yank/paste system clipboard

Named

"ay "ap

Yank/paste register 'a'

Windows

Split

:sp :vs

Horizontal, vertical

Navigate

Ctrl+w h/j/k/l

Move between windows

Close

Ctrl+w q

Close window

Search/Replace

Replace

:%s/old/new/g

All in file

Confirm

:%s/old/new/gc

With confirmation

Lines

:g/pattern/d

Delete matching lines

20.2. Cross-Site References

  • Vim Reference (Infra-Ops) - Quick reference for infrastructure tasks