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 calledvim-tinyor the POSIXvi). The fullvimpackage 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
| Key | Action |
|---|---|
h | Move left one character |
j | Move down one line |
k | Move up one line |
l | Move 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
| Key | Action |
|---|---|
w | Jump to the start of the next word |
b | Jump to the start of the previous word |
e | Jump to the end of the current/next word |
W | Jump to the next WORD (whitespace-delimited) |
B | Jump to the previous WORD |
E | Jump 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
| Key | Action |
|---|---|
0 | Jump 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
| Key | Action |
|---|---|
gg | Jump to the first line of the file |
G | Jump to the last line of the file |
42G | Jump to line 42 |
:42 | Jump to line 42 (command-line mode) |
Ctrl-d | Scroll down half a page |
Ctrl-u | Scroll up half a page |
Ctrl-f | Scroll down a full page |
Ctrl-b | Scroll up a full page |
H | Jump to the top of the screen (High) |
M | Jump to the middle of the screen (Middle) |
L | Jump to the bottom of the screen (Low) |
Hands-On: Practice Navigation
- 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 -
- 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
- Press
:q!to quit without saving.
Entering and Leaving Insert Mode
There are several ways to enter insert mode, each placing your cursor differently:
| Key | Action |
|---|---|
i | Insert before the cursor |
I | Insert at the beginning of the line |
a | Append after the cursor |
A | Append at the end of the line |
o | Open a new line below and enter insert mode |
O | Open 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
| Command | Action |
|---|---|
x | Delete the character under the cursor |
X | Delete the character before the cursor |
r{char} | Replace the character under the cursor with {char} |
dd | Delete (cut) the entire current line |
yy | Yank (copy) the entire current line |
p | Paste after the cursor |
P | Paste before the cursor |
u | Undo the last change |
Ctrl-r | Redo (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:
| Command | Action |
|---|---|
dw | Delete from cursor to next word |
d$ or D | Delete from cursor to end of line |
d0 | Delete from cursor to beginning of line |
dG | Delete from cursor to end of file |
dgg | Delete from cursor to beginning of file |
cw | Change word (delete word + enter insert mode) |
c$ or C | Change to end of line |
ci" | Change inside quotes |
di( | Delete inside parentheses |
da{ | Delete around braces (including the braces) |
yaw | Yank 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
| Command | Action |
|---|---|
/pattern | Search forward for "pattern" |
?pattern | Search backward for "pattern" |
n | Jump to the next match |
N | Jump 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:
| Command | Action |
|---|---|
:w | Save (write) the file |
:q | Quit (fails if there are unsaved changes) |
:wq | Save and quit |
:x | Save and quit (only writes if changes were made) |
ZZ | Save and quit (normal mode shortcut for :x) |
:q! | Quit without saving (discard changes) |
:w newfile.txt | Save as a different filename |
:e otherfile.txt | Open a different file |
:r filename | Read and insert the contents of another file |
:!command | Run a shell command without leaving Vim |
:r !command | Insert 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.
| Key | Mode | Selection Type |
|---|---|---|
v | Visual | Character-wise selection |
V | Visual Line | Whole-line selection |
Ctrl-v | Visual Block | Column/rectangular selection |
Common Visual Mode Workflow
- Enter visual mode (
v,V, orCtrl-v) - Move the cursor to extend the selection
- 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.
| Register | Description |
|---|---|
"" | Default (unnamed) register -- last delete or yank |
"0 | Yank register -- last yank only (not deletes) |
"a to "z | Named 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) requiresvim-gtk3on Debian/Ubuntu,vim-X11on Fedora/RHEL, orgvimon Arch. The terminalvimpackage often lacks clipboard support. Check withvim --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 vimgives the editor root privileges. If you have untrusted plugins or a complex.vimrc, this can be a security risk. Consider usingsudoeditorsudo -einstead, 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
-
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. -
Macro Challenge: Create a file with 20 lines of
key=valuepairs. Record a macro that convertskey=valuetoexport KEY="value"(uppercase the key, add export and quotes). Apply it to all 20 lines. -
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.
-
Search and Replace: Download a sample config file (e.g., a default
nginx.conf) and practice replacing all IP addresses matching127.0.0.1with0.0.0.0. -
Bonus Challenge: Open your
~/.bashrcin 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.