Get out safely
Save and quit
Esc then :wqQuit and change nothing
Esc then :q!Undo what I just did
Esc then uNothing I type appears
Press
i firstIt says readonly
:w !sudo tee %Undo everything since opening
:e!
When in doubt, press Esc. It always returns you to command mode from anywhere, and every colon command on this sheet starts there. Pressing it twice does no harm.
The three modes
| Mode | What it is for, and how to get there |
|---|---|
| Command | Where you start. Keys are commands, not text. Esc returns here. |
| Insert | Typing text. Enter it with i, a, o and leave with Esc. |
| Visual | Selecting. Enter with v, V or Ctrl+v. |
| The colon line | Not a mode but where :w, :q and :s are typed |
This is the whole reason vi feels hostile. In Notepad every key types. Here a key means one thing while editing and another while commanding, so typing a sentence in command mode runs a dozen commands. Check the bottom of the screen:
-- INSERT -- means you are typing.
Moving
| Where | Key |
|---|---|
| Left, down, up, right | h j k l, arrows also work |
| Start and end of the line | 0 and $ |
| First non-blank character | ^ |
| Next and previous word | w and b |
| End of the current word | e |
| Top of the file | gg |
| Bottom of the file | G |
| Line 42 | 42G, or :42 |
| Page down and up | Ctrl+f and Ctrl+b |
| Matching bracket | % |
| Back to where you jumped from | Ctrl+o |
Starting to type
| Where the cursor lands | Key |
|---|---|
| Before the character under the cursor | i |
| After it | a |
| At the start of the line | I |
| At the end of the line | A |
| On a new line below | o |
| On a new line above | O |
| Replace one character, staying in command mode | r then the character |
| Overwrite until Esc | R |
Delete, change, copy
Almost everything is an action plus a target. Learn the two lists and you get every combination.
| Action | Means |
|---|---|
d | delete, and put it on the clipboard |
c | change: delete, then start typing |
y | yank, which is copy |
> and < | indent and outdent |
| Target | Means |
|---|---|
w | to the start of the next word |
$ | to the end of the line |
0 | to the start of the line |
G | to the end of the file |
iw | the word under the cursor |
i" | what is inside the quotes |
ip | this paragraph or block |
| So, in practice | Keys |
|---|---|
| Delete this line | dd |
| Delete five lines | 5dd |
| Delete to the end of the line | D, same as d$ |
| Delete a word | dw, or diw from anywhere in it |
| Delete from here to the end of the file | dG |
| Retype a word | ciw |
| Replace what is inside quotes | ci" |
| Retype the rest of the line | C |
| Copy this line | yy |
| Copy three lines | 3yy |
| Paste below, and above | p and P |
| Delete one character | x |
| Join this line with the next | J |
| Repeat the last change | . |
| Undo, and redo | u and Ctrl+r |
The dot is the shortcut nobody mentions. Make a change once, move to the next place, press
. and it happens again. With n after a search it turns a repetitive edit into two keystrokes per occurrence.
Selecting
| Task | Keys |
|---|---|
| Select character by character | v, then move |
| Select whole lines | V, then j or k |
| Select a rectangular block | Ctrl+v, then move |
| Delete the selection | d |
| Copy the selection | y |
| Indent the selection | >, repeat with . |
| Replace inside the selection only | :s/old/new/g after selecting |
| Comment out several lines | Ctrl+v, move down, I, type #, Esc |
| Select the whole file | ggVG |
| Cancel the selection | Esc |
Block mode earns its keep on config files.
Ctrl+v down twenty lines, then I# and Esc, comments out the whole block in one move. The same with x uncomments it.
Searching
| Task | Keys |
|---|---|
| Search forward | /text then Enter |
| Search backward | ?text |
| Next and previous hit | n and N |
| Search for the word under the cursor | * |
| Ignore case for this search | /text\c |
| Clear the highlighting | :noh |
| Jump to a line number | :42 |
Find and replace
| Scope | Command |
|---|---|
| First match on this line | :s/old/new/ |
| Every match on this line | :s/old/new/g |
| Whole file | :%s/old/new/g |
| Whole file, confirm each one | :%s/old/new/gc |
| Lines 10 to 20 only | :10,20s/old/new/g |
| From here to the end | :.,$s/old/new/g |
| Ignoring case | :%s/old/new/gi |
| When the text contains slashes | :%s#/opt/old#/opt/new#g |
| Delete every line containing a word | :g/debug/d |
| Keep only lines containing a word | :v/keep/d |
Use /gc the first time. Confirming each replacement costs a few keystrokes and prevents the classic accident of replacing a word inside twenty other words.
y accepts, n skips, a accepts the rest, q stops.
Files and saving
| Task | Command |
|---|---|
| Save | :w |
| Save and quit | :wq, or ZZ |
| Quit, discarding changes | :q! |
| Save as another name | :w /tmp/copy.conf |
| Save only the selected lines elsewhere | select, then :w /tmp/part.txt |
| Reload the file, losing changes | :e! |
| Open another file | :e /etc/hosts |
| Insert another file at the cursor | :r /etc/hosts |
| Insert the output of a command | :r !date |
| Save a file you opened without sudo | :w !sudo tee %, then :q! |
| Open two files side by side | vi -O a.conf b.conf, switch with Ctrl+w then w |
Back up before editing anything load-bearing.
cp /etc/fstab /etc/fstab.bak costs one second. A broken fstab or sshd_config costs a console session, and on a remote server that may mean a trip to the datacentre.
Settings worth typing
| Effect | Command |
|---|---|
| Line numbers | :set number, off with :set nonumber |
| Highlight search hits | :set hlsearch |
| Case-insensitive searching | :set ignorecase |
| Stop auto-indent mangling a paste | :set paste, undo with :set nopaste |
| Show what mode you are in | :set showmode |
| Make it permanent | put the same lines, without the colon, in ~/.vimrc |
Pasting into a terminal and getting a staircase? That is auto-indent applying to every pasted line.
:set paste before pasting and :set nopaste after solves it, and it is the single most useful setting on this sheet.
vi on ESXi and minimal systems
| Situation | What to expect |
|---|---|
| ESXi host | BusyBox vi, not vim. Movement, i, dd, :w, :q! and :%s work. |
| What is missing there | No visual block mode, no Ctrl+r redo, no syntax colour, no ~/.vimrc |
| Config edits on ESXi | Changes can be reverted by the periodic backup. Run /sbin/auto-backup.sh to persist them. |
| Containers and appliances | Often BusyBox vi as well, sometimes no editor at all |
| When there is no editor | cat > file <<'EOF', type the content, then EOF on its own line |
| Debian and Ubuntu | vi may be a minimal vim. nano is usually installed and easier. |
FAQ
It will not let me save and says readonly.
You opened the file without the rights to write it. Either quit with
:q! and reopen with sudo vi file, or save through sudo from inside: :w !sudo tee % followed by :q!. The second works because tee writes the file as root while vi keeps the buffer.
It warns about a swap file and offers Recover.
Another session had the file open, or vi was killed before saving. If nobody else is editing, press
R to recover, save, then delete the leftover .filename.swp. If you do not need the unsaved changes, press D to delete the swap and open normally.
My arrow keys insert letters like A and B.
A very old vi over a terminal that is not sending proper escape codes. Use
h j k l instead, which always work, and if it keeps happening set TERM=xterm before starting.
I made a mess. How far back can I undo?
In vim,
u repeatedly walks back through the whole session and Ctrl+r walks forward again. BusyBox vi on ESXi typically undoes only the last change, so on those systems :e! to reload the file from disk is the real safety net.
Is it worth learning at all if nano exists?
Learn the twenty keys on this sheet, not more. nano is friendlier and fine when it is installed, but vi is the editor that is always there, including on an ESXi host at two in the morning, and that is precisely when you do not want to be learning it.