Vim Basics: Essential Commands and Practical Techniques

Vim Basics: Essential Commands and Practical Techniques

What you'll be able to do

  • Switch modes and recover from a stuck Vim session unaided
  • Choose between saving, discarding, and force-quitting
  • Run search and replace safely in confirm mode

Prerequisites (read these first)

What You'll Learn

  • You will be able to switch Vim modes and get yourself out of a stuck session.
  • You will pick up the minimum workflow for movement, editing, and search/replace used in real work.
  • You will be able to choose between saving, discarding, and force-quitting as the situation demands.
  • You will be able to set up a comfortable .vimrc for any new server.
  • You will keep working even when only vi is installed on a remote box.

Who this is for: anyone who now has to SSH into a server and fix a config file. If you have ever opened Vim and failed to close it, this article is aimed squarely at you.

Terms defined up front

Every term Vim guides assume is defined once, here.

  • A mode is the current state that decides what a keypress does. Vim keeps the state for moving and the state for typing separate.
  • Normal mode is the state for moving, deleting, and copying. Some material calls it "command mode", but this article says "normal mode" to keep it distinct from command-line mode below.
  • Insert mode is the state where a keypress puts that character into the text.
  • Command-line mode is the state you enter with : to type instructions such as save, quit, or replace. These are also called Ex commands.
  • A buffer is the file content Vim holds in memory. Editing the buffer does not change the file on disk yet — the file changes only when :w writes it.
  • Yank is Vim's name for a copy operation. Read it as "copy".
  • A swap file is a hidden .swp file that stores edits as you go, so the content can be recovered after an abnormal exit.

Quick Summary (the practical workflow)

  • After launching, always think in normal mode first (Esc)
  • The editing loop is: i → edit → Esc:w — four steps
  • If you get stuck, press Esc twice, then :q! to force-quit
  • For config files, use sudoedit, not sudo vim

Assumed environment

  • OS: Ubuntu or any Linux
  • Vim 8+ or Neovim (vi-compatibility quirks are noted)
  • Mainly remote server work over SSH

1. Modes: 80% of the Battle

Conclusion: Vim's difficulty is its modes; learn normal, insert, visual, command-line first.

The single biggest reason beginners give up on Vim is modes. Once you internalize them, the rest is just memorizing commands.

Mode How to enter What you can do
Normal Esc Move, delete, copy
Insert i / a / o Type text
Visual v / V Select ranges
Command-line : Save, quit, replace

Rule of thumb: When anything weird happens, hit Esc twice to return to normal mode.

You can tell which mode you are in from the bottom-left of the screen: -- INSERT -- for insert mode, -- VISUAL -- for visual mode, and nothing at all for normal mode. Pressing Esc is always harmless, so press it whenever you are unsure.

1-1. Entering Insert Mode (Which Key to Use)

i   # Insert before cursor
a   # Insert after cursor (great at end of line)
o   # Open new line below
O   # Open new line above
I   # Insert at start of line
A   # Insert at end of line

At first, just use i and o. Once comfortable, A (append at end) becomes a daily driver.

2. Save and Quit: The #1 Stuck Point

Conclusion: :w saves, :wq saves and quits, :q! discards; these three end the stuck problem.

This is where the "I can't escape Vim" memes come from. Memorize this section.

:w           # Write (save)
:q           # Quit
:wq          # Save and quit
:x           # Save and quit (only writes if changed)
ZZ           # Same as :wq in normal mode
:q!          # Quit without saving
:w !sudo tee % > /dev/null   # Save a file you forgot to open with sudo (details in 2-1)

Plain :q refuses to quit if there are unsaved changes. Use :q! to discard, :wq to keep them.

2-1. Recovering from a sudo Mistake

Classic accident: open /etc/something with vim, edit it, then hit Permission denied on save.

:w !sudo tee % > /dev/null
  • % expands to the current filename
  • tee writes to disk; > /dev/null discards stdout
  • After saving, :q! (file is already on disk, so ! is fine)

The proper fix: edit config files with sudoedit /etc/ssh/sshd_config (alias sudo -e). It opens a temp copy and writes back on exit.

3. Movement: Skip the Mouse

Conclusion: Move with hjkl, by word, line, screen, or search, all in normal mode.

These work in normal mode only. They do nothing in insert mode.

3-1. Character-Level

h j k l   # left down up right

Mnemonic: j looks like a hook going down, k punches up.

3-2. Word, Line, Screen

w / b      # Next / previous word start
e          # End of word
0 / ^ / $  # Start of line / first non-blank / end of line
gg / G     # Top / bottom of file
:42        # Jump to line 42
Ctrl-d / Ctrl-u   # Half-screen down / up
Ctrl-f / Ctrl-b   # Full-screen down / up

3-3. Search-Based Movement

/word      # Search forward
?word      # Search backward
n / N      # Next / previous match
*          # Search forward for word under cursor

Practical tip: When tailing a log, hit G to jump to the end, then ?ERROR to search backward.

4. Editing: The Bare Minimum

Conclusion: A few commands cover daily edits: x, dd, yy, p, u, and the repeat dot.

x          # Delete one character
dd         # Delete a line (into clipboard)
3dd        # Delete 3 lines
dw         # Delete a word
d$ / D     # Delete to end of line
yy         # Yank (copy) a line
3yy        # Yank 3 lines
p / P      # Paste (after / before)
u          # Undo
Ctrl-r     # Redo
.          # Repeat last change

The most powerful command is . (dot). It repeats your last edit. Run dw once, move the cursor, hit . — same edit applied.

4-1. Numeric Prefixes

Almost any command takes a count prefix.

5j         # Move 5 lines down
10x        # Delete 10 characters
3yy        # Yank 3 lines

5. Search and Replace: Daily Driver

Conclusion: Search with /pattern and replace with :%s/foo/bar/g; use gc to confirm safely.

/pattern   # Forward (regex allowed)
?pattern   # Backward
n / N      # Next / previous

5-2. Replace (The Important One)

:s/foo/bar/        # First match on current line
:s/foo/bar/g       # All matches on current line
:%s/foo/bar/g      # All matches in the file
:%s/foo/bar/gc     # Same, with confirmation
:5,10s/foo/bar/g   # Only lines 5-10

The trailing g (global) means "every match on the line", c (confirm) means "ask about each one", and % sets the range to the whole file.

5-3. Regex Pitfalls

Vim's regex flavor differs subtly from POSIX extended regex.

:%s/\v(\w+)\s+\1/\1/g   # \v enables "very magic" — closer to standard regex

With \v, you no longer need to escape (), +, or ?. Save it as muscle memory; it prevents a lot of head-scratching.

6. Multiple Files and Windows

Conclusion: Switch files with buffers and view them side by side with split windows.

6-1. Buffers (Multiple Files)

:e other.txt    # Open another file
:ls             # List open buffers
:b 2            # Switch to buffer 2
:bn / :bp       # Next / previous buffer
:bd             # Close buffer

6-2. Split Windows

:sp file.txt    # Horizontal split
:vsp file.txt   # Vertical split
Ctrl-w w        # Cycle through windows
Ctrl-w q        # Close current window
Ctrl-w =        # Equalize window sizes

A common setup: logs on one side, config file on the other. Pair with tmux over SSH for an even stronger workflow.

7. Visual Mode: Operate on a Selection

Conclusion: Select a range with v, V, or Ctrl-v, then delete, yank, indent, or replace.

v          # Start character-wise selection
V          # Start line-wise selection
Ctrl-v     # Start block (rectangular) selection

With a selection active:

d          # Delete
y          # Yank
>          # Indent
<          # Outdent
:s/a/b/    # Replace within selection only

Block selection trick: To prefix multiple lines with # (comment them out), use Ctrl-v → select lines → I#Esc. It applies the prefix to all selected lines at once.

8. .vimrc: A Minimal Setup

Conclusion: Put a minimal ~/.vimrc with line numbers, search, and indent for comfort.

Write this in ~/.vimrc. It's small enough that you can retype it on a fresh server in 30 seconds.

" Basics
set number              " Show line numbers
set ruler               " Show cursor position
set showcmd             " Show partial commands
set wildmenu            " Better command completion

" Search
set hlsearch            " Highlight matches
set incsearch           " Incremental search
set ignorecase          " Case-insensitive
set smartcase           " But case-sensitive if pattern has uppercase

" Indent
set autoindent          " Auto indent
set expandtab           " Tab -> spaces
set tabstop=4           " Tab width
set shiftwidth=4        " Indent width

" Safety
set backup              " Keep backup files
set backupdir=~/.vim/backup,/tmp
set undofile            " Persistent undo
set undodir=~/.vim/undo

" UI
syntax on               " Syntax highlighting
set background=dark     " Assume dark terminal

Create the directories first: mkdir -p ~/.vim/backup ~/.vim/undo.

On a server with only vi (Vim's compatibility mode), some set options silently fail. Check :version to see what's available.

9. Escape Routes When Stuck

Conclusion: Stuck states like can't quit or can't save have mechanical escape routes.

Common stuck states and the mechanical fix.

9-1. Can't Quit

Esc Esc :q!

Always return to normal mode first, then force-quit.

9-2. Can't Save (Read-Only)

:set noreadonly
:w

Or use the sudo trick: :w !sudo tee % > /dev/null.

9-3. Frozen Screen

Ctrl-q        # Resume a terminal stopped by Ctrl-s

Ctrl-s pauses the terminal itself — not a Vim problem.

9-4. A Column of ~ Down the Left Edge

This is not a fault. ~ is Vim's ordinary marker for "there is no line here", and it always fills the area below the end of the file. No action is needed.

Likewise, finding extra files such as file.txt~ after editing is not a fault. Those are backup files created by set backup in your .vimrc (covered below), which is a different thing from a swap file. Delete them if you do not want them.

9-5. E325: ATTENTION on Startup

A swap file (.swp) is left over. It is a sign that Vim did not exit cleanly last time, or that someone else has the same file open.

E325: ATTENTION
Found a swap file by the name ".file.txt.swp"
ls -la .*.swp
:recover       # Run inside Vim

Review what :recover restores, save anything you need, and only then run rm .file.txt.swp. Swap file names take the form ". + original filename + .swp".

10. vi vs Vim vs Neovim

Conclusion: vi is usually Vim's compat mode, Vim is the standard, Neovim is a modern fork.

Name What it really is Notes
vi Usually Vim running in vi-compatible mode Some settings disabled
Vim Vi IMproved The de facto standard
Neovim A fork of Vim Lua config, built-in LSP, modern internals
which vi
ls -l $(which vi)
/usr/bin/vi
lrwxrwxrwx 1 root root 20 Feb 15  2024 /usr/bin/vi -> /etc/alternatives/vi

What sits to the right of -> is the real binary. On Ubuntu it goes through /etc/alternatives/vi to vim.basic or vim.tiny. Which one it is decides what settings are available.

Minimal Ubuntu installs may only have vim-tiny. Install the full version with sudo apt install vim.

11. Summary: The Workflow You'll Use Tomorrow

Copy-paste template: minimum daily workflow

# 1. Open
vim file.txt

# 2. Move in normal mode
gg              # Top of file
/keyword        # Search

# 3. Switch to insert mode
i               # Start editing
(edit)
Esc             # Back to normal

# 4. Save and quit
:wq

# If you mess up
:q!             # Discard and quit

Completion Checklist

  • [ ] Told which mode you are in from the bottom-left indicator
  • [ ] Chose deliberately between :wq (save and quit) and :q! (discard and quit)
  • [ ] Checked the targets with /pattern before a global replace
  • [ ] Edited config files via sudoedit, or after taking a backup
  • [ ] Ran ps aux | grep vim before deleting a .swp file

Don't do this

  • Typing :wq while still in insert mode (you write :wq into the file)
  • Opening a file with sudo vim /etc/... and getting stuck on save — use sudoedit instead
  • Reflexively deleting .swp files — someone may be editing
  • Bloating your .vimrc — it stops being portable across servers

Next Reading