Vim Essentials

Why This Matters

It is 2 AM. You are SSH'd into a production server that just started throwing 502 errors. The application config has a typo, and the only editors installed on this minimal server image are vi and nano. Your colleague used nano, accidentally saved the file with trailing whitespace that broke the YAML parser, and now the service will not start at all.

Vim (and its predecessor vi) is the one editor you can count on being available on virtually every Unix and Linux system ever built -- from a Raspberry Pi to a mainframe, from a Docker container to a rescue boot disk. Knowing Vim is not about editor wars or productivity hacks. It is about having a reliable, powerful tool in your hands no matter where you land.

Beyond availability, Vim's modal editing model is genuinely efficient once you internalize it. Instead of holding modifier keys for every operation, you switch between modes -- one for navigating, one for inserting text, one for selecting, one for running commands. This separation means your hands rarely leave the home row, and complex edits become composable sequences of simple keystrokes.

You do not need to master Vim today. You need to be competent enough to open a file, make a change, save it, and quit. Everything beyond that is a bonus that will come with practice.


Try This Right Now

Open a terminal and run:

vimtutor

This launches Vim's built-in interactive tutorial. It takes about 30 minutes. If you have never used Vim before, vimtutor is the single best starting point. It teaches by doing.

If vimtutor is not available:

# Debian/Ubuntu
sudo apt install vim

# Fedora/RHEL
sudo dnf install vim-enhanced

# Arch
sudo pacman -S vim

Distro Note: Most minimal installations include vi (often a stripped-down version called vim-tiny or the POSIX vi). The full vim package gives you syntax highlighting, undo history, and all the features covered in this chapter.


Understanding Modal Editing

Most editors you have used -- nano, Notepad, VS Code -- are modeless. Every key you press inserts a character. To do anything else, you hold Ctrl, Alt, or Shift.

Vim is different. It has modes. The mode you are in determines what your keypresses do.

+----------------------------------------------------------+
|                     VIM MODES                            |
+----------------------------------------------------------+
|                                                          |
|                   NORMAL MODE                            |
|               (navigation, commands)                     |
|                    |    ^                                 |
|              i,a,o |    | Esc                             |
|                    v    |                                 |
|                INSERT MODE                               |
|              (typing text)                                |
|                                                          |
|   From NORMAL:     |    From NORMAL:                     |
|         v, V, Ctrl-v    |         : (colon)               |
|              |           |              |                  |
|              v           |              v                  |
|         VISUAL MODE      |       COMMAND-LINE MODE        |
|      (selecting text)    |    (ex commands like :w :q)    |
|              |           |              |                  |
|         Esc  |           |         Enter or Esc            |
|              v           |              v                  |
|         NORMAL MODE      |         NORMAL MODE            |
+----------------------------------------------------------+

The Four Essential Modes

Normal Mode -- This is where Vim starts. Your keys are commands, not characters. Pressing j moves the cursor down, not inserting the letter "j". This feels alien at first. Give it time.

Insert Mode -- This is the familiar typing mode. Press i to enter insert mode, type your text, press Esc to return to normal mode.

Visual Mode -- For selecting text. Press v for character-wise, V for line-wise, or Ctrl-v for block (column) selection.

Command-Line Mode -- Press : from normal mode to type commands at the bottom of the screen: saving files, quitting, searching and replacing, running shell commands.

Think About It: Why would separating navigation from text input be an advantage? Consider how much time you spend navigating versus actually typing new text when editing config files.


Opening Files and the Basics

Opening Vim

# Open a file
vim /etc/hostname

# Open a file at a specific line number
vim +42 /etc/nginx/nginx.conf

# Open a file and search for a pattern
vim +/server_name /etc/nginx/nginx.conf

# Open multiple files
vim file1.conf file2.conf

# Open in read-only mode
vim -R /etc/passwd

The Status Line

When you open a file in Vim, look at the bottom of the screen:

"myfile.conf" 42L, 1337C

This tells you the filename, line count, and character count. When you are in different modes, the bottom-left will show:

-- INSERT --          (you are in insert mode)
-- VISUAL --          (you are in visual mode)
-- VISUAL LINE --     (line-wise visual mode)
-- VISUAL BLOCK --    (block visual mode)
:                     (command-line mode)
(nothing)             (normal mode)

Essential Motions (Normal Mode)

In normal mode, you navigate without touching the mouse. Here are the motions you need to know, organized from most basic to most useful.

Character and Line Movement

KeyAction
hMove left one character
jMove down one line
kMove up one line
lMove right one line

Think of it this way: j looks like a down arrow. h is on the left, l is on the right.

You can prefix any motion with a number:

5j      Move down 5 lines
10k     Move up 10 lines
3l      Move right 3 characters

Word Movement

KeyAction
wJump to the start of the next word
bJump to the start of the previous word
eJump to the end of the current/next word
WJump to the next WORD (whitespace-delimited)
BJump to the previous WORD
EJump to the end of the current/next WORD

The difference between w and W: lowercase w treats punctuation as word boundaries. W only treats whitespace as boundaries. So in server_name=localhost, pressing w would stop at _, =, and l. Pressing W would jump over the whole thing.

Line Movement

KeyAction
0Jump to the first column of the line
^Jump to the first non-blank character
$Jump to the end of the line
f{char}Jump forward to the next occurrence of {char} on this line
F{char}Jump backward to the previous occurrence of {char}
t{char}Jump forward to just before {char}

File Movement

KeyAction
ggJump to the first line of the file
GJump to the last line of the file
42GJump to line 42
:42Jump to line 42 (command-line mode)
Ctrl-dScroll down half a page
Ctrl-uScroll up half a page
Ctrl-fScroll down a full page
Ctrl-bScroll up a full page
HJump to the top of the screen (High)
MJump to the middle of the screen (Middle)
LJump to the bottom of the screen (Low)

Hands-On: Practice Navigation

  1. Open the system dictionary file (a large file, perfect for practice):
vim /usr/share/dict/words

If that file does not exist, use any long file, or create one:

seq 1 500 | vim -
  1. Try these commands in sequence:
gg          Go to the top
G           Go to the bottom
50G         Go to line 50
Ctrl-d      Scroll down
Ctrl-u      Scroll up
0           Go to start of line
$           Go to end of line
w           Jump word by word
b           Jump back word by word
  1. Press :q! to quit without saving.

Entering and Leaving Insert Mode

There are several ways to enter insert mode, each placing your cursor differently:

KeyAction
iInsert before the cursor
IInsert at the beginning of the line
aAppend after the cursor
AAppend at the end of the line
oOpen a new line below and enter insert mode
OOpen a new line above and enter insert mode

To leave insert mode, press Esc. Some people also use Ctrl-[, which does the same thing and is easier to reach.

Think About It: Why does Vim offer six different ways to enter insert mode? Think about the most common editing patterns: adding to the end of a line (A), starting a new config entry below the current one (o), inserting before a specific character (i).


Editing Commands (Normal Mode)

This is where Vim starts to feel powerful. These commands follow a grammar: operator + motion (or operator + text object).

Basic Editing

CommandAction
xDelete the character under the cursor
XDelete the character before the cursor
r{char}Replace the character under the cursor with {char}
ddDelete (cut) the entire current line
yyYank (copy) the entire current line
pPaste after the cursor
PPaste before the cursor
uUndo the last change
Ctrl-rRedo (undo the undo)
.Repeat the last change

The Operator + Motion Grammar

Vim commands are composable. An operator followed by a motion applies that operation over the motion's range:

d       = delete operator
w       = word motion
dw      = delete from cursor to next word

c       = change operator (delete + enter insert mode)
$       = end of line motion
c$      = change from cursor to end of line

y       = yank (copy) operator
gg      = beginning of file
ygg     = yank from cursor to beginning of file

Common combinations:

CommandAction
dwDelete from cursor to next word
d$ or DDelete from cursor to end of line
d0Delete from cursor to beginning of line
dGDelete from cursor to end of file
dggDelete from cursor to beginning of file
cwChange word (delete word + enter insert mode)
c$ or CChange to end of line
ci"Change inside quotes
di(Delete inside parentheses
da{Delete around braces (including the braces)
yawYank a word (including surrounding whitespace)

Text Objects

Text objects let you operate on structured chunks of text. They start with i (inside) or a (around):

ciw     Change inside word
daw     Delete a word (word + surrounding whitespace)
ci"     Change inside double quotes
da"     Delete around double quotes (quotes + content)
ci(     Change inside parentheses
da[     Delete around square brackets
cit     Change inside HTML/XML tag

Hands-On: Editing Practice

Create a practice file:

vim /tmp/vim-practice.txt

Press i to enter insert mode and type:

server_name = oldhostname
port = 8080
log_level = debug
database_host = 192.168.1.100
database_port = 5432

Press Esc to return to normal mode. Now practice:

gg          Go to line 1
f=          Jump to the = sign
w           Move to "oldhostname"
cw          Change word -- type "newhostname", then Esc
j           Move down to port line
$           Go to end of line
r0          Replace the last "0" with "0" (no change, just practice)
j           Move to log_level line
fdbug       Oops -- that's not right. Use: f d to find "d", then cw to change word

Let us do that last one properly:

j           Move to the log_level line
fd          Jump to "d" in "debug"
cw          Change word -- type "info", then Esc

Save your work with :w and quit with :q (or combine: :wq).


Searching and Replacing

Searching

CommandAction
/patternSearch forward for "pattern"
?patternSearch backward for "pattern"
nJump to the next match
NJump to the previous match
*Search forward for the word under the cursor
#Search backward for the word under the cursor

Example: To find all occurrences of "error" in a log file:

/error

Press Enter, then n to cycle through matches.

Search and Replace

The substitute command uses this syntax:

:[range]s/pattern/replacement/[flags]

Common examples:

:s/old/new/           " Replace first 'old' on the current line
:s/old/new/g          " Replace all 'old' on the current line
:%s/old/new/g         " Replace all 'old' in the entire file
:%s/old/new/gc        " Replace all, but ask for confirmation each time
:10,20s/old/new/g     " Replace all 'old' on lines 10-20

Hands-On: Search and Replace

vim /tmp/search-practice.txt

Enter insert mode (i) and paste:

server1 host=10.0.0.1 port=8080
server2 host=10.0.0.2 port=8080
server3 host=10.0.0.3 port=8080
server4 host=10.0.0.4 port=9090

Press Esc, then:

/8080           Search for 8080 -- cursor jumps to first match
n               Next match
n               Next match
N               Previous match

:%s/8080/3000/g     Replace all 8080 with 3000
u                   Undo that change

:%s/8080/3000/gc    Replace with confirmation -- press y/n for each

Saving, Quitting, and File Operations

This is the section everyone needs. If you remember nothing else from this chapter, remember these:

CommandAction
:wSave (write) the file
:qQuit (fails if there are unsaved changes)
:wqSave and quit
:xSave and quit (only writes if changes were made)
ZZSave and quit (normal mode shortcut for :x)
:q!Quit without saving (discard changes)
:w newfile.txtSave as a different filename
:e otherfile.txtOpen a different file
:r filenameRead and insert the contents of another file
:!commandRun a shell command without leaving Vim
:r !commandInsert the output of a shell command

WARNING: :q! discards ALL unsaved changes without confirmation. Use it deliberately, not out of frustration.

Hands-On: File Operations

vim /tmp/fileops-practice.txt

Enter insert mode and type a few lines, then:

Esc             Return to normal mode
:w              Save the file
:!ls /tmp       Run ls without leaving Vim -- press Enter to return
:r !date        Insert the current date/time into the file
:w backup.txt   Save a copy as backup.txt
:q              Quit

Visual Mode: Selecting Text

Visual mode lets you select text and then operate on it.

KeyModeSelection Type
vVisualCharacter-wise selection
VVisual LineWhole-line selection
Ctrl-vVisual BlockColumn/rectangular selection

Common Visual Mode Workflow

  1. Enter visual mode (v, V, or Ctrl-v)
  2. Move the cursor to extend the selection
  3. Apply an operator: d (delete), y (yank), c (change), > (indent), < (unindent)

Hands-On: Block Selection

Visual block mode (Ctrl-v) is especially useful for editing columnar data:

vim /tmp/block-practice.txt

Enter insert mode and type:

host1  10.0.0.1   active
host2  10.0.0.2   active
host3  10.0.0.3   active
host4  10.0.0.4   active

Now add a comment character to the beginning of every line:

gg              Go to the first line
Ctrl-v          Enter visual block mode
3j              Select down 4 lines (first + 3 more)
I               Capital I -- insert at block beginning
#               Type the # character
Esc             Press Escape -- the # appears on all selected lines

To remove those comments:

gg              Go to the first line
Ctrl-v          Enter visual block mode
3j              Select down 4 lines
x               Delete the selected column

Registers: Vim's Clipboards

When you delete or yank text, it goes into a register. Vim has many registers, not just one clipboard.

RegisterDescription
""Default (unnamed) register -- last delete or yank
"0Yank register -- last yank only (not deletes)
"a to "zNamed registers -- you control what goes in
"+System clipboard (if Vim is compiled with +clipboard)
"*Primary selection (X11 middle-click paste)

Using Named Registers

"ayy        Yank current line into register a
"bdd        Delete current line into register b
"ap         Paste from register a
"bp         Paste from register b
:reg        View all registers and their contents

This is useful when you need to juggle multiple pieces of text.

Distro Note: System clipboard support ("+ register) requires vim-gtk3 on Debian/Ubuntu, vim-X11 on Fedora/RHEL, or gvim on Arch. The terminal vim package often lacks clipboard support. Check with vim --version | grep clipboard.


Macros: Repeating Complex Edits

Macros let you record a sequence of keystrokes and replay them. This is extraordinarily useful for repetitive edits.

Recording and Playing Macros

qa          Start recording into register a
(do stuff)  Your keystrokes are recorded
q           Stop recording
@a          Play back the macro in register a
@@          Repeat the last played macro
5@a         Play the macro 5 times

Hands-On: Macro Editing

Suppose you have a list of hostnames and need to wrap each in quotes and add a comma:

vim /tmp/macro-practice.txt

Enter insert mode and type:

server1
server2
server3
server4
server5

Press Esc, then:

gg          Go to line 1
qa          Start recording into register a
I"          Insert " at beginning of line
Esc         Back to normal mode
A",         Append ", at end of line
Esc         Back to normal mode
j           Move down one line
q           Stop recording
4@a         Play the macro 4 times (for the remaining 4 lines)

Result:

"server1",
"server2",
"server3",
"server4",
"server5",

Think About It: How would you modify this macro to also add a trailing comma on all lines except the last? (Hint: record without j, use a count, then manually edit the last line.)


Configuring Vim: .vimrc Basics

Vim reads its configuration from ~/.vimrc (or ~/.vim/vimrc). Here is a sensible starting configuration:

vim ~/.vimrc
" Basic settings
set nocompatible          " Use Vim defaults, not vi
syntax on                 " Enable syntax highlighting
set number                " Show line numbers
set relativenumber        " Show relative line numbers
set ruler                 " Show cursor position
set showcmd               " Show partial commands
set showmatch             " Highlight matching brackets

" Indentation
set tabstop=4             " Tab width = 4 spaces
set shiftwidth=4          " Indent width = 4 spaces
set expandtab             " Use spaces instead of tabs
set autoindent            " Copy indent from current line
set smartindent           " Smart autoindenting for C-like languages

" Search
set hlsearch              " Highlight search matches
set incsearch             " Incremental search (highlight as you type)
set ignorecase            " Case-insensitive search...
set smartcase             " ...unless you use uppercase letters

" Usability
set wildmenu              " Enhanced command-line completion
set scrolloff=5           " Keep 5 lines visible above/below cursor
set backspace=indent,eol,start  " Make backspace work normally
set mouse=a               " Enable mouse support (optional)

" File handling
set encoding=utf-8        " UTF-8 encoding
set fileformats=unix,dos  " Prefer Unix line endings
set nobackup              " Don't create backup files
set noswapfile            " Don't create swap files (live dangerously)

After saving, reload with :source ~/.vimrc or restart Vim.


Debug This

You SSH into a server to fix an Nginx config. You open the file:

vim /etc/nginx/sites-available/default

You make your changes, then try to save:

:w

You get this error:

E45: 'readonly' option is set (add ! to override)

You try :w! and get:

E212: Can't open file for writing

What is happening? You opened the file as a non-root user and do not have write permission. Here are your options:

Option 1: Save to a temporary file and move it:

:w /tmp/nginx-fix.conf

Then in another terminal: sudo cp /tmp/nginx-fix.conf /etc/nginx/sites-available/default

Option 2: Use the tee trick (write with sudo from within Vim):

:w !sudo tee % > /dev/null

This pipes the buffer through sudo tee, where % is Vim's shorthand for the current filename. You will be prompted for your password.

Option 3: Open the file with sudo from the start:

sudo vim /etc/nginx/sites-available/default

WARNING: Running sudo vim gives the editor root privileges. If you have untrusted plugins or a complex .vimrc, this can be a security risk. Consider using sudoedit or sudo -e instead, which copies the file, lets you edit the copy, then moves it back.


Quick Reference Card

+---------------------------------------------------------------+
|                    VIM QUICK REFERENCE                         |
+---------------------------------------------------------------+
| MOVEMENT           | EDITING            | FILES               |
| h/j/k/l  arrows    | i    insert before | :w   save           |
| w/b      word jump  | a    append after  | :q   quit           |
| 0/$      line edges | o/O  new line      | :wq  save+quit      |
| gg/G     file edges | dd   delete line   | :q!  force quit     |
| Ctrl-d/u half-page  | yy   copy line     | :e   open file      |
| /pattern search     | p    paste         | :!   shell cmd      |
| n/N      next/prev  | u    undo          |                     |
| *        word search| Ctrl-r redo        |                     |
|                     | .    repeat        |                     |
+---------------------------------------------------------------+
| VISUAL             | MACROS             | SEARCH/REPLACE      |
| v   character      | qa  record to a    | /text  search fwd   |
| V   line           | q   stop record    | ?text  search back  |
| C-v block          | @a  play macro     | :%s/a/b/g  replace  |
| d/y after select   | @@  repeat last    | :%s/a/b/gc confirm  |
+---------------------------------------------------------------+

What Just Happened?

+------------------------------------------------------------------+
|                        CHAPTER RECAP                              |
+------------------------------------------------------------------+
|                                                                   |
|  Vim uses MODAL EDITING: Normal, Insert, Visual, Command-Line.  |
|                                                                   |
|  Normal mode is home base -- navigation and commands.            |
|  Press i/a/o to enter Insert mode, Esc to return.               |
|                                                                   |
|  Commands are COMPOSABLE: operator + motion = action.            |
|    dw = delete word,  c$ = change to end of line                |
|                                                                   |
|  Search with /pattern, replace with :%s/old/new/g               |
|                                                                   |
|  Save with :w, quit with :q, force quit with :q!                |
|                                                                   |
|  Visual mode (v/V/Ctrl-v) for selecting, then apply operator.   |
|                                                                   |
|  Macros (qa...q, @a) automate repetitive edits.                 |
|                                                                   |
|  Customize Vim with ~/.vimrc for a better experience.            |
|                                                                   |
+------------------------------------------------------------------+

Try This

  1. Config File Editing: Open /etc/fstab (read-only: vim -R /etc/fstab), practice navigating with motions. Jump to specific lines, search for "uuid", use * on a word.

  2. Macro Challenge: Create a file with 20 lines of key=value pairs. Record a macro that converts key=value to export KEY="value" (uppercase the key, add export and quotes). Apply it to all 20 lines.

  3. Visual Block Power: Create a file with 10 lines of data separated by spaces. Use visual block mode to delete a column, add a column, and reorder columns.

  4. Search and Replace: Download a sample config file (e.g., a default nginx.conf) and practice replacing all IP addresses matching 127.0.0.1 with 0.0.0.0.

  5. Bonus Challenge: Open your ~/.bashrc in Vim. Using only Vim commands (no mouse), navigate to a specific alias, duplicate it, change the duplicate's name, and save. Time yourself. Repeat until you can do it in under 10 seconds.