Surviving Vim: Exiting, Modes, Navigation, Editing and Search-and-Replace Commands
Key takeaways
Enough Vim to stop being stuck: quitting safely, understanding normal, insert and visual modes, navigation, editing, search and replace, and the save and quit commands.
Introduction: “Opened Vim but Cannot Exit!”
When you SSH into a server, there’s no GUI editor. Vi/Vim is an essential text editor pre-installed on almost all Linux/Unix systems.
But when you first open Vim:
- Cannot type text
- Don’t know how to exit
- Mouse doesn’t work
- Commands are unusual
All four symptoms have one cause: Vim starts in a mode where keys are commands, not text. Typing a word like “hello” in that mode moves the cursor (h, l), and an o opens a new line; the file changes in ways that look random. Once you know that ESC always returns to that command mode and that commands beginning with : are typed at the bottom of the screen, Vim stops being a trap. You do not need to become a Vim power user to edit a config file over SSH; the first sections of this guide are enough for that, and the later ones explain why experienced users find the model fast.
What This Guide Covers:
- Exit in 10 seconds (most searched question)
- Mode concept (Normal, Insert, Visual, Command)
- Practical commands (navigation, editing, search, replace)
- Essential settings (.vimrc)
- Cheat sheet
Emergency Exit: Quitting Vim
Most Searched Question
# When you opened Vim and cannot exit
# Step 1: Press ESC key multiple times
ESC ESC ESC
# Step 2: Type one of these
:q # Quit (refuses if there are unsaved changes)
:q! # Force quit (discard changes)
:wq # Save and quit
:x # Save and quit (only if changed)
ZZ # Same as :x (faster)
Exit by Situation
| Situation | Command | Description |
|---|---|---|
| No changes made | :q | Just quit |
| Want to save changes | :wq or ZZ | Save and quit |
| Want to discard changes | :q! | Force quit |
| Save with filename | :w filename | Save as |
| Force save readonly | :w! | Only if you have permission |
The messages Vim prints at the bottom tell you which of these you need. :q on a modified buffer answers E37: No write since last change (add ! to override), which is Vim protecting your edits; add ! only if you really want to discard them. If :w fails with E212: Can't open file for writing, you do not have permission for that path, and :w! will not help, because ! only overrides Vim’s own readonly flag, not the file system; the FAQ at the end shows how to write through sudo. When several files are open, :qa quits all of them and :wqa saves and quits all.
One more trap from other editors: pressing Ctrl+S out of habit does not save. In most terminals it pauses output (XOFF flow control), so Vim appears frozen. Press Ctrl+Q to resume; nothing was lost.
Vi vs Vim Difference
Vi (Visual Editor)
- Developed in 1976 (almost 50 years ago!)
- Pre-installed on all Unix/Linux
- Minimal features
Vim (Vi IMproved)
- Developed in 1991 (improved Vi)
- Additional features:
- Syntax highlighting
- Multiple undo/redo
- Plugin system
- Split windows
- Auto-completion
- Visual mode
On most Linux distributions, typing vi actually starts Vim, sometimes a minimal build (Debian and Ubuntu ship vim-tiny by default) that runs in a vi-compatible mode: arrow keys in insert mode may print letters like A and B, and undo only toggles the last change. Installing the full vim package fixes both. Minimal container images often have neither editor, in which case vi may be BusyBox’s small implementation, which supports the basic commands in this guide. Neovim (nvim) is a modern fork with the same editing model; everything here applies to it too.
Understanding Modes
Vim’s Core: Modes
Vim is a modal editor. Same key behaves differently depending on mode.
Normal Mode (Default)
- Vim starts in this mode
- Execute commands (navigate, delete, copy)
- Cannot type text
- ESC returns here anytime
# Normal mode commands
dd # Delete current line
yy # Copy current line
p # Paste
u # Undo
Insert Mode (Input)
- Text input mode
- Type like normal editor
- ESC returns to Normal mode
# Enter Insert mode
i # Insert at cursor
I # Insert at line start
a # Append after cursor
A # Append at line end
o # Open line below
O # Open line above
Visual Mode (Selection)
- Text selection mode
- Select block then copy/delete
v # Character-wise selection
V # Line-wise selection
Ctrl+v # Block-wise selection (vertical)
Command Mode (Commands)
- Starts with
: - Save, quit, search, replace
:w # Save
:q # Quit
:wq # Save and quit
:%s/old/new/g # Replace
The reason for modes is that most editing time is spent moving around and changing existing text, not typing new text. With a separate command mode, every key on the keyboard becomes a command without needing Ctrl or Alt, so “delete this line” is dd instead of a mouse selection. The price is having to know which mode you are in; set showmode (on by default in Vim) displays -- INSERT -- at the bottom when you are typing text, and when in doubt, ESC is always safe to press.
Basic Navigation
hjkl Instead of Arrow Keys
# Basic movement (arrow keys work but hjkl is faster)
h # ← Left
j # ↓ Down
k # ↑ Up
l # → Right
Why hjkl?: vi was written on the Lear Siegler ADM-3A terminal, whose keyboard had no separate arrow keys; the arrows were printed on the H, J, K and L keys. Today arrow keys work fine in Vim, and hjkl is simply faster because your hands stay on the home row.
Word Movement
w # Next word start
W # Next word start (space-separated)
e # Next word end
E # Next word end (space-separated)
b # Previous word start
B # Previous word start (space-separated)
Line Movement
0 # Line start
^ # Line start (excluding spaces)
$ # Line end
gg # File start
G # File end
:n # Go to line n (e.g., :42)
42G # Go to line 42
Screen Movement
Ctrl+f # Page down (forward)
Ctrl+b # Page up (backward)
Ctrl+d # Half page down
Ctrl+u # Half page up
H # Screen top (High)
M # Screen middle (Middle)
L # Screen bottom (Low)
Text Editing
Delete
x # Delete character at cursor
X # Delete character before cursor
dd # Delete current line
D # Delete from cursor to line end
dw # Delete word
d$ # Delete from cursor to line end
d0 # Delete from cursor to line start
dG # Delete from cursor to file end
dgg # Delete from cursor to file start
These are not separate commands to memorize. They follow one grammar: operator + motion. d is the delete operator, and whatever motion follows says how far: dw deletes to where w would move (the start of the next word), d$ to the end of the line, dG to the end of the file. The same motions work with c (change: delete and enter insert mode) and y (yank, i.e. copy), and a count in front repeats the motion: d3w deletes three words, 3dd three lines. Doubling the operator (dd, cc, yy) applies it to the whole line.
Text objects extend the grammar with “inside” and “around”: ciw changes the word under the cursor wherever the cursor is inside it, di" deletes everything inside the surrounding quotes, da( deletes a parenthesized expression including the parentheses, and yip copies a paragraph. Once this clicks, you can guess commands you have never seen, which is what makes Vim fast for people who use it daily.
Change
r # Replace character (1 char)
R # Replace mode
cw # Change word
cc # Change line
C # Change from cursor to line end
s # Delete char and enter insert mode
S # Delete line and enter insert mode
Undo/Redo
u # Undo
Ctrl+r # Redo
. # Repeat last command
Undo works in units of changes: everything typed in one insert session, from entering insert mode to pressing ESC, is undone by a single u. That is one reason to leave insert mode often. . repeats the last change, including the text inserted during it, so a pattern like “cw new name ESC, then n to jump to the next match and . to repeat” renames several occurrences one by one while letting you skip the ones you want to keep.
Search and Replace
Search
/pattern # Search forward
?pattern # Search backward
n # Next match
N # Previous match
* # Search word under cursor
# # Search word under cursor backward
Example:
/error # Search "error"
n # Next error
N # Previous error
Replace
:s/old/new/ # Replace first old with new in current line
:s/old/new/g # Replace all old with new in current line
:%s/old/new/g # Replace all old with new in entire file
:%s/old/new/gc # Replace all with confirmation
:5,10s/old/new/g # Replace in lines 5-10
Practical Examples:
# Change print to logging in Python
:%s/print(/logging.info(/g
# Replace tabs with 4 spaces
:%s/\t/ /g
# Remove trailing spaces
:%s/\s\+$//g
The pattern part is a regular expression, which causes most surprises. ., *, [ and ~ are special, so replacing a literal path like /var/log needs either escaping or a different delimiter: :%s#/var/log#/srv/log#g avoids a forest of backslashes. Vim’s default regex flavor also differs from grep or Perl: + and ? need a backslash (\+, as in the trailing-space example), while ( and ) are literal unless escaped, which is why the print( example works as written. Starting a pattern with \v (“very magic”) makes it behave more like other regex engines. Without the g flag, only the first match on each line is replaced, not the first match in the file.
Two habits make replacement safer. Search first with /pattern and press n a few times to see what matches, then run :%s//new/g with an empty pattern, which reuses the last search. And use the c flag for anything risky; at each match Vim asks y/n/a/q, and a replaces all remaining ones once you trust it. If a replacement goes wrong anyway, a single u undoes the whole :%s command.
Copy, Paste, Delete
Copy (Yank)
yy # Copy current line
Y # Copy current line (same as yy)
yw # Copy word
y$ # Copy from cursor to line end
yG # Copy from cursor to file end
Paste
p # Paste after cursor
P # Paste before cursor
Copy with Visual Mode
# 1. Enter Visual mode with v
# 2. Select range with hjkl
# 3. Copy with y (or cut with d)
# 4. Paste with p
Example:
# Copy 5 lines
5yy # Copy 5 lines from current
p # Paste
# Block copy
Ctrl+v # Block selection mode
jjjj # Select 4 lines down
lll # Select 3 chars right
y # Copy
p # Paste
Delete in Vim is really cut: dd, dw and x put the deleted text into the same unnamed register that p pastes from. That makes “cut and paste” natural (dd then p moves a line), but it also produces the most common Vim clipboard surprise: you yank a line with yy, delete another line to make room, press p, and get the deleted line instead of the yanked one. The yanked text is still there in register 0, which only yanks write to, so "0p pastes it. In block mode, Ctrl+v may be intercepted by the terminal as “paste” (Windows Terminal, some Linux terminals); Ctrl+q is the usual alternative in that case.
Pasting from the system clipboard into Vim running in a terminal has its own trap. The terminal types the text as if you were typing, so auto-indent adds indentation on every line and code arrives in an ever-deeper staircase. Modern Vim versions detect bracketed paste in most terminals and avoid this; on older setups, :set paste before pasting and :set nopaste afterwards fixes it.
Save and Quit
Save
:w # Save
:w filename # Save as
:w! # Force save (readonly file)
:w >> file # Append to file
:5,10w file # Save lines 5-10
Quit
:q # Quit (no changes)
:q! # Force quit (discard changes)
:wq # Save and quit
:x # Save and quit (only if changed)
ZZ # Same as :x (faster)
ZQ # Same as :q!
The difference between :wq and :x is small but real: :wq always writes the file, updating its modification time even when nothing changed, while :x writes only if there are changes. That matters for tools that react to file timestamps, such as make, file watchers or config reloaders. :w >> file and :5,10w file are handy on servers for extracting part of a log into a separate file without leaving the editor.
If an SSH connection drops while you are editing, Vim leaves a swap file (.filename.swp) next to the file. Next time you open it, you see E325: ATTENTION ... Found a swap file. Press R to recover the unsaved changes, save, then delete the swap file (Vim offers D for that in recent versions); press E only if you are sure no other session is editing the file.
Split Windows
Horizontal/Vertical Split
:split filename # Horizontal split
:sp filename # Horizontal split (short)
:vsplit filename # Vertical split
:vsp filename # Vertical split (short)
# Split empty window
:split # Horizontal
:vsplit # Vertical
Navigate Between Windows
Ctrl+w h # Left window
Ctrl+w j # Down window
Ctrl+w k # Up window
Ctrl+w l # Right window
Ctrl+w w # Next window
Splits are most useful on servers for comparing two config files side by side or keeping a log open while editing a script. Each window shows a buffer, and several windows can show the same buffer, so edits in one appear in the other immediately. :q closes the current window, not the whole editor, and :only closes all the others. For comparing files specifically, vimdiff a.conf b.conf (or vim -d) opens them in splits with the differences highlighted.
Essential Settings (.vimrc)
Create .vimrc File
# Create .vimrc in home directory
vim ~/.vimrc
Recommended Basic Settings
" Basic settings
set nocompatible " Disable Vi compatibility
syntax on " Syntax highlighting
set number " Line numbers
set relativenumber " Relative line numbers
set cursorline " Highlight cursor line
set ruler " Show cursor position
" Indentation
set autoindent " Auto indent
set smartindent " Smart indent
set tabstop=4 " Tab size
set shiftwidth=4 " Auto indent size
set expandtab " Convert tabs to spaces
" Search
set hlsearch " Highlight search results
set incsearch " Incremental search
set ignorecase " Ignore case
set smartcase " Case-sensitive if uppercase
" UI
set showmatch " Show matching brackets
set wildmenu " Command auto-completion
set laststatus=2 " Always show status bar
set showcmd " Show command
" Convenience
set mouse=a " Enable mouse
set clipboard=unnamed " Use system clipboard
set encoding=utf-8 " UTF-8 encoding
set backspace=indent,eol,start " Backspace behavior
" File type settings
filetype plugin indent on
" Color theme
colorscheme desert " Color theme (built-in)
A few of these settings need context. set nocompatible is redundant in Vim when a ~/.vimrc exists (its presence already switches compatibility off), but it is harmless and matters if the file is loaded with vim -u. ignorecase plus smartcase makes /error match “Error” and “ERROR” while /Error matches only that exact case. expandtab inserts spaces when you press Tab, which is what most code styles want, and wrong for Makefiles, which require real tabs; filetype plugin indent on lets the Makefile filetype turn it back off. set clipboard=unnamed only works if Vim was built with clipboard support (vim --version shows +clipboard); on Linux with X11 or Wayland, unnamedplus is the register tied to the Ctrl+C/Ctrl+V clipboard, and over SSH there is usually no system clipboard at all. set mouse=a lets you click to move the cursor, but it also stops the terminal’s own text selection from working the usual way; holding Shift while selecting usually restores it.
On a shared server, keep this file in your own home directory and do not edit /etc/vimrc; the settings are personal, and colleagues may expect the defaults.
Cheat Sheet
Mode Switching
| Command | Action |
|---|---|
ESC | To Normal mode |
i | Insert mode (at cursor) |
a | Insert mode (after cursor) |
o | Insert mode (new line below) |
v | Visual mode |
: | Command mode |
Top 20 Essential Commands
| Command | Action | Frequency |
|---|---|---|
:wq | Save and quit | ⭐⭐⭐⭐⭐ |
:q! | Force quit | ⭐⭐⭐⭐⭐ |
dd | Delete line | ⭐⭐⭐⭐⭐ |
yy | Copy line | ⭐⭐⭐⭐ |
p | Paste | ⭐⭐⭐⭐⭐ |
u | Undo | ⭐⭐⭐⭐⭐ |
/pattern | Search | ⭐⭐⭐⭐ |
:%s/old/new/g | Replace all | ⭐⭐⭐⭐ |
gg | File start | ⭐⭐⭐ |
G | File end | ⭐⭐⭐ |
0 | Line start | ⭐⭐⭐ |
$ | Line end | ⭐⭐⭐ |
dw | Delete word | ⭐⭐⭐ |
cw | Change word | ⭐⭐⭐ |
A | Insert at line end | ⭐⭐⭐ |
o | New line below | ⭐⭐⭐ |
Ctrl+f | Page down | ⭐⭐ |
Ctrl+b | Page up | ⭐⭐ |
. | Repeat last command | ⭐⭐⭐ |
* | Search word | ⭐⭐ |
Learning Vim without memorizing a cheat sheet
Vim ships with an interactive tutorial that is worth the half hour: run vimtutor in a terminal. It edits a copy of a practice file, so nothing can go wrong, and it builds the muscle memory for the commands above much faster than reading about them. After that, add one new command a day only when you notice yourself doing something the slow way, such as holding j to scroll instead of searching with /.
Frequently Asked Questions (FAQ)
Q. How do I save a file I opened without permission to write it?
A. If you get “E45: ‘readonly’ option is set” or a permission error on :w, you can write through sudo with :w !sudo tee % > /dev/null, then reload with :e!. Another option is to save to a different path with :w ~/filename and move it afterwards. To avoid this, open system files with sudo vim or sudoedit from the start.