If you work with Linux servers, you probably know the basic Vi commands:
i insert text
Esc leave insert mode
:w save
:q quit
:wq save and quit
That’s enough to edit a configuration file.
But it’s not enough to edit files quickly.
The real power of Vi starts when you stop thinking of it as a text editor and start thinking in terms of motions, operators, objects, and commands.
Instead of moving the cursor one character at a time, you can tell Vi exactly what you want:
delete this word
change everything inside these quotes
jump to the next occurrence
replace this value
move this line
repeat that change
For example, instead of doing this:
→ → → → → → Backspace Backspace Backspace
you can simply use:
dw
Or instead of selecting text with a mouse, you can use:
ci"
to change everything inside quotation marks.
Once these commands become muscle memory, editing configuration files over SSH becomes much faster.
See also: Mastering the Linux Command Line — Your Complete Free Training Guide
Let’s go beyond i and :wq.
Table of Contents
First: Understand the Vi Mental Model
Before learning advanced commands, understand the basic idea behind Vi.
Vi has different modes.
The two you’ll use most are:
Normal mode
Insert mode
When Vi starts, you’re normally in Normal mode.
Press:
i
and you enter Insert mode.
Press:
Esc
and you’re back in Normal mode.
The important thing is that most advanced Vi commands are designed to be used from Normal mode.
For example:
dw
means:
d + w
where:
d = delete
w = move forward by a word
This gives you a very useful formula:
operator + motion
Once you understand this, many Vi commands stop looking random.
1. Move Faster Than the Arrow Keys
You can use the arrow keys, but Vi’s movement commands are much more powerful.
Basic movement:
h left
j down
k up
l right
But you can also jump by words.
w
moves to the beginning of the next word.
b
moves backward to the beginning of the previous word.
e
moves to the end of the current or next word.
For example:
The PostgreSQL server is running normally
^
Press:
w
and the cursor jumps to:
The PostgreSQL server is running normally
^
Instead of pressing the right arrow repeatedly, you’re moving semantically.
2. Jump to the Beginning or End of a Line
These are commands you’ll use constantly.
0
moves to the absolute beginning of the line.
^
moves to the first non-whitespace character.
$
moves to the end of the line.
For example:
server_name nginx.example.com;
^
Press:
^
and the cursor moves to:
server_name nginx.example.com;
^
the s.
Press:
$
and it jumps to:
server_name nginx.example.com;
^
This is particularly useful when editing configuration files with indentation.
3. Delete With Motions
Here’s where Vi becomes interesting.
The d command means:
delete
Combine it with a movement command.
For example:
dw
means:
Delete from here to the next word.
Similarly:
de
deletes to the end of the word.
d$
deletes from the cursor to the end of the line.
And:
d0
deletes from the cursor to the beginning of the line.
For example:
server_name old-server.example.com;
^
Place the cursor before old-server and run:
d$
Everything from the cursor to the end of the line is removed.
4. Delete an Entire Line
You don’t need to select the entire line.
Simply use:
dd
For example:
server {
listen 80;
server_name example.com;
root /var/www/html;
}
Put the cursor anywhere on:
listen 80;
and press:
dd
The entire line disappears.
This is one of the first commands worth memorizing.
5. Delete Multiple Lines
You can combine numbers with commands.
For example:
5dd
means:
Delete five lines.
Similarly:
3dw
deletes three words.
And:
2dd
deletes two lines.
This pattern is incredibly useful:
number + command
For example:
10j
moves down ten lines.
5w
moves forward five words.
3dd
deletes three lines.
6. Undo and Redo
Made a mistake?
Use:
u
to undo.
Need to redo the change?
Use:
Ctrl-r
For example:
dd
deletes a line.
Then:
u
brings it back.
Then:
Ctrl-r
applies the deletion again.
A simple workflow is:
make change
|
v
check result
|
+--> wrong? --> u
|
+--> correct? --> continue
7. Change Instead of Delete
The c command means:
change
It’s similar to delete, except Vi puts you into Insert mode afterward.
For example:
cw
means:
Change the current word.
Suppose you have:
server_name old-server.example.com;
^
Use:
cw
Then type:
new-server.example.com
and press:
Esc
You have replaced the word without manually deleting it first.
8. Change the Rest of a Line
This is extremely useful:
c$
It means:
Change from the cursor to the end of the line.
For example:
server_name old-server.example.com;
^
Press:
c$
Then type:
new-server.example.com;
and press Esc.
This is often faster than:
d$
i
9. Change an Entire Line
Use:
cc
or:
S
Both can change the current line.
For example:
listen 80;
Press:
cc
Then type:
listen 8080;
and press:
Esc
The indentation is generally preserved more conveniently than manually deleting the line.
10. The Power of Text Objects
This is where Vi really starts to feel different from conventional editors.
Consider:
server_name "old-server.example.com";
Suppose you want to replace only the text inside the quotes.
You could move the cursor around manually.
Or use:
ci"
Break it down:
c
change
i"
inside quotes
So:
ci"
means:
Change the text inside the quotation marks.
Type:
new-server.example.com
and press:
Esc
Now you have:
server_name "new-server.example.com";
That’s much faster.
11. Common Text Objects
Some useful text objects are:
iw inner word
aw a word
i" inside double quotes
a" around double quotes
i' inside single quotes
a' around single quotes
i( inside parentheses
a( around parentheses
i[ inside brackets
a[ around brackets
i{ inside braces
a{ around braces
For example:
echo "hello world"
Put the cursor anywhere inside:
hello world
Then:
ci"
changes the contents.
With:
di"
you delete the contents.
With:
yi"
you copy the contents.
The pattern is:
operator + text object
For example:
d + i"
c + i(
y + i{
Once you recognize this pattern, a lot of Vi becomes predictable.
12. Delete Inside Parentheses
Suppose you have:
systemctl restart nginx --no-block
Or a programming example:
connect(host="db01", port=5432)
Put the cursor inside the parentheses and use:
di(
The contents disappear.
If you want to remove the parentheses too:
da(
This distinction is important:
di(
means:
delete inside parentheses
while:
da(
means:
delete around parentheses
13. Change Text Inside Quotes
This is one of my favorite practical Vi commands.
Suppose you have:
DATABASE_HOST="old-db.example.com"
Put the cursor anywhere inside the quoted value:
ci"
Type:
new-db.example.com
Press:
Esc
Done.
No mouse.
No Shift+Arrow.
No repeated Backspace.
14. Find a Character With f
Suppose you have:
server_name web01.example.com;
You want to jump to the first ;.
Use:
f;
The cursor jumps directly to the semicolon.
Similarly:
ft
moves forward until the character before the next t.
You can repeat the search with:
;
and go backward with:
,
This becomes particularly powerful when combined with operators.
For example:
d;
can delete from the current position through the next occurrence of the searched character, depending on the motion context.
15. Find a Character Without Moving Onto It
There is another useful command:
t
For example:
t;
means:
Move until just before the next
;.
This is useful when you want to operate on text but keep the delimiter.
For example:
dt;
means:
Delete until the next semicolon, but don’t delete the semicolon itself.
This is a very useful pattern when editing configuration lines.
16. Jump Between Matching Brackets
Suppose you have:
if (server_status == "ready") {
start_service();
}
Put the cursor on:
(
and press:
%
Vi jumps to the matching:
)
The same works with:
()
[]
{}
This is extremely useful when editing code or complex configuration files.
For example:
location /api/ {
proxy_pass http://backend;
}
Place the cursor on { and press:
%
Vi jumps to the corresponding }.
17. Search for Text
Use:
/pattern
For example:
/server_name
Press Enter.
Vi jumps to the next occurrence.
To find the next match:
n
To find the previous match:
N
This is much faster than scrolling through a large configuration file.
For example:
/Listen
can quickly take you to the relevant section of a large sshd_config.
18. Search and Replace
One of the most useful Vi commands for Linux administrators is substitution.
The basic syntax is:
:s/old/new/
For example:
:s/oldhost/newhost/
replaces the first matching occurrence on the current line.
To replace every occurrence on the current line:
:s/oldhost/newhost/g
To replace throughout the entire file:
:%s/oldhost/newhost/g
This is much faster than manually editing dozens of lines.
19. Replace With Confirmation
Before performing a large replacement, you can ask Vi to confirm each change.
Use:
:%s/oldhost/newhost/gc
The c means:
confirm
Vi will ask you whether each match should be changed.
This is useful when the same text appears in multiple contexts and you don’t want to blindly replace everything.
20. Replace Only on Specific Lines
You don’t always need to modify the entire file.
For example:
:10,20s/old/new/g
means:
Replace
oldwithnewbetween lines 10 and 20.
You can also use:
:1,10s/foo/bar/g
for the first ten lines.
And:
:.,$s/foo/bar/g
means:
Replace from the current line to the end of the file.
21. Copy and Paste With Yank
In Vi, copying is usually called yanking.
The command is:
y
For example:
yy
copies the current line.
Then:
p
pastes after the current line.
And:
P
pastes before the current line.
For example:
server {
listen 80;
}
Put the cursor on:
listen 80;
Press:
yy
Then:
p
You get:
server {
listen 80;
listen 80;
}
22. Move Lines With dd and p
Here’s a surprisingly useful trick.
Suppose you have:
line 1
line 2
line 3
Put the cursor on:
line 1
Run:
dd
Then move to line 3 and press:
p
The line can be moved around the file.
So:
dd
p
isn’t only for deleting and pasting.
It’s also a simple way to move lines.
23. Copy Multiple Lines
Use a count:
3yy
This yanks three lines.
Then:
p
pastes them.
Similarly:
5dd
deletes five lines.
The count syntax makes bulk editing much faster.
24. Visual Mode
Sometimes you really do want to select text.
Vi provides Visual mode.
Character selection:
v
Line selection:
V
Block selection:
Ctrl-v
These are three different tools.
For example:
v
lets you select individual characters.
V
selects entire lines.
And:
Ctrl-v
creates a rectangular block.
25. Visual Block Mode Is Extremely Useful
Suppose you have:
server1 10.10.1.10
server2 10.10.1.11
server3 10.10.1.12
server4 10.10.1.13
You want to add:
prod-
to the beginning of several lines.
Press:
Ctrl-v
Select the vertical block.
Then:
I
Type:
prod-
Then press:
Esc
Vi inserts the text across the selected lines.
This is one of the features that makes Vi incredibly useful for structured configuration files.
26. Repeat the Last Change With .
The dot command:
.
repeats your last change.
This sounds simple, but it can save a huge amount of time.
Suppose you change:
server1
to:
web01
Then move to another occurrence and press:
.
Vi repeats the previous editing operation.
For repetitive changes:
make one change
move
.
move
.
move
.
This is often much faster than repeating the entire command sequence.
27. The Dot Command Is a Big Productivity Booster
Consider:
server_name app01;
server_name app02;
server_name app03;
server_name app04;
You change one line using:
cw
Then type the new value.
After that, move to the next matching location and press:
.
You can repeat the same operation.
The key is to make your first edit in a way that can be repeated cleanly.
That’s one reason experienced Vi users often think about:
“How can I make this change repeatable?”
rather than:
“How do I edit this one line?”
28. Record a Macro
If the same sequence needs to be performed many times, use a macro.
Start recording into register a:
qa
Perform your commands.
Then stop recording:
q
Replay it with:
@a
For example:
qa
perform:
dd
then:
q
Now:
@a
repeats the recorded operation.
You can repeat the macro with:
@@
which runs the last executed macro again.
29. Registers: Vi’s Clipboard System
Vi doesn’t have just one clipboard.
It has registers.
For example:
"ayy
means:
Yank the current line into register
a.
Then:
"ap
pastes from register a.
This is useful when you need to copy several different pieces of text without overwriting your previous yank.
You can inspect registers with:
:reg
This can show named registers, the unnamed register, search history, and other stored information.
30. The System Clipboard
Depending on how Vim was built, you may also have access to the system clipboard.
Check:
vim --version | grep clipboard
You might see:
+clipboard
or:
-clipboard
If clipboard support is available, commands such as:
"+yy
can yank a line into the system clipboard.
And:
"+p
can paste from it.
This is particularly useful when working over SSH or inside terminal environments.
31. Jump to a Specific Line
Need to go directly to line 500?
Use:
:500
Or:
500G
Both can take you to a specific line.
You can also use:
gg
to jump to the beginning of the file.
And:
G
to jump to the end.
These commands are extremely useful for large configuration files.
32. Jump Half a Screen at a Time
For large files, you don’t always want to scroll one line at a time.
Useful commands include:
Ctrl-d
scroll down roughly half a screen.
Ctrl-u
scroll up roughly half a screen.
Ctrl-f
page forward.
Ctrl-b
page backward.
And:
zz
centers the current line on the screen.
That last one is particularly useful after searching.
33. Join Lines
Suppose you have:
server_name
example.com;
Put the cursor on the first line and press:
J
The lines are joined:
server_name example.com;
This is useful when cleaning up wrapped configuration or text.
34. Replace a Single Character
Use:
r
followed by a character.
For example:
rx
replaces the current character with x.
This is different from:
cw
because you don’t enter Insert mode.
For example:
port=5433
If the cursor is on 3 and you want 2:
r2
Done.
35. Replace Multiple Characters
The R command enters Replace mode.
R
Then you can type replacement characters continuously.
Press:
Esc
when you’re done.
This is useful when replacing a sequence of characters without inserting new text.
36. Indent Multiple Lines
Select lines using Visual mode:
V
Then:
>
to indent.
Use:
<
to remove indentation.
You can also repeat the indentation with:
>>
for the current line.
And:
<<
to decrease indentation.
This is especially useful when editing scripts or configuration files.
37. Auto-Indent
For a selected block, you can use:
=
to auto-indent.
For example:
V
select several lines, then:
=
Depending on the file type and Vim configuration, Vim can adjust indentation automatically.
For a whole file:
gg=G
This means:
gg go to beginning
= indent
G through the end
It’s a surprisingly useful command.
38. Edit Multiple Files
Vi can also work with multiple files.
For example:
vim file1.conf file2.conf file3.conf
You can move between buffers with:
:next
and:
:previous
You can see open buffers with:
:buffers
Then switch to a buffer:
:buffer 2
This is useful when comparing or editing several related configuration files.
39. Split the Screen
Open another file in a horizontal split:
:split file2.conf
Or vertically:
:vsplit file2.conf
Move between windows with:
Ctrl-w h
Ctrl-w j
Ctrl-w k
Ctrl-w l
For example:
+-------------------------+-------------------------+
| | |
| nginx.conf | upstream.conf |
| | |
| | |
+-------------------------+-------------------------+
This is much more convenient than constantly opening and closing files.
40. Compare Two Files
Vim can also be used for side-by-side comparison.
For example:
vimdiff old.conf new.conf
You’ll get a split view showing differences between the files.
This is particularly useful for configuration changes:
vimdiff /etc/ssh/sshd_config \
/etc/ssh/sshd_config.backup
Instead of manually comparing two large files, Vim highlights the differences.
41. A Practical SSH Configuration Example
Suppose you’re editing:
sudo vi /etc/ssh/sshd_config
You want to find:
PasswordAuthentication
Instead of scrolling:
/PasswordAuthentication
Press Enter.
Then:
n
to find the next match.
Suppose you find:
PasswordAuthentication yes
Move to yes and use:
cw
Type:
no
Then:
Esc
Now:
PasswordAuthentication no
Save:
:w
Validate the configuration before restarting SSH:
sudo sshd -t
Then restart the service if appropriate:
sudo systemctl restart sshd
This is a much more realistic workflow than memorizing isolated Vi commands.
42. Another Real Example: Editing PostgreSQL Configuration
Suppose you’re editing:
sudo vi /var/lib/pgsql/data/postgresql.conf
You need to change:
max_connections = 100
to:
max_connections = 500
Search:
/max_connections
Then move to the value and use:
cw
Type:
500
Press:
Esc
If you need to make the same style of change elsewhere, the dot command can often repeat your last edit.
For a known global replacement, you could instead use:
:%s/max_connections = 100/max_connections = 500/g
The important skill is knowing which editing method fits the task.
43. A Practical Log File Example
Suppose you’re investigating a large log file:
vi /var/log/messages
You want to find an error:
/ERROR
Then:
n
to move between errors.
If you find something interesting, mark the location:
ma
This creates mark a.
You can continue exploring the file.
Later:
'a
takes you back to that location.
Marks are useful when investigating large configuration files or logs.
44. Marks Are Easy to Overlook
You can create multiple marks:
ma
mb
mc
Then jump back:
'a
'b
'c
For example:
ma
at the beginning of a configuration section.
Search elsewhere.
Then:
'a
to return.
It’s a small feature, but very useful during troubleshooting.
45. Use Numbers With Almost Everything
One of the easiest ways to become faster in Vi is to stop repeating commands manually.
Instead of:
j
j
j
j
j
use:
5j
Instead of:
dd
dd
dd
use:
3dd
Instead of:
w
w
w
use:
3w
The general pattern is:
[count][command]
This is one of the fundamental ideas behind Vi’s command language.
46. The Real Power: Combining Commands
The best Vi users don’t necessarily memorize hundreds of commands.
They understand how commands combine.
For example:
d$
means:
delete + move to end of line
ci"
means:
change + inside quotes
da(
means:
delete + around parentheses
yap
means:
yank + a paragraph
Once you learn the building blocks, you can construct commands instead of memorizing them individually.
Advanced Vi Command Cheat Sheet
| Command | Action |
|---|---|
w | Next word |
b | Previous word |
e | End of word |
0 | Beginning of line |
^ | First non-whitespace character |
$ | End of line |
gg | Beginning of file |
G | End of file |
n | Next search match |
N | Previous search match |
% | Matching bracket |
f<char> | Find character |
t<char> | Move before character |
dd | Delete line |
dw | Delete word |
d$ | Delete to end of line |
cc | Change line |
cw | Change word |
c$ | Change to end of line |
ci" | Change inside quotes |
di( | Delete inside parentheses |
da( | Delete around parentheses |
yy | Yank line |
p | Paste after |
P | Paste before |
u | Undo |
Ctrl-r | Redo |
. | Repeat last change |
v | Visual character mode |
V | Visual line mode |
Ctrl-v | Visual block mode |
J | Join lines |
r<char> | Replace one character |
R | Replace mode |
> | Indent |
< | Unindent |
gg=G | Auto-indent file |
qa ... q | Record macro in register a |
@a | Run macro a |
:s/old/new/ | Replace on current line |
:%s/old/new/g | Replace throughout file |
:w | Save |
:q | Quit |
:wq | Save and quit |
The Commands Worth Learning First
You don’t need to memorize the entire table.
If you’re currently comfortable with:
i
Esc
:w
:q
:wq
start with these:
w
b
e
0
$
dd
dw
cw
ci"
di(
yy
p
u
Ctrl-r
.
/
n
%
gg
G
Then learn:
f
t
V
Ctrl-v
:
%s
macros
registers
That’s enough to dramatically change how you edit files.
Final Thoughts
Vi becomes much more interesting once you stop treating it like a keyboard-controlled version of a GUI editor.
The real idea is:
operator + motion
and:
operator + text object
For example:
dw
Delete a word.
c$
Change to the end of the line.
ci"
Change inside quotes.
di(
Delete inside parentheses.
yap
Copy a paragraph.
Then add:
count
when you need to repeat something:
5dd
3w
10j
And when you’ve found a useful editing sequence:
.
repeats it.
That’s the point where Vi starts to feel less like an old-fashioned editor and more like a small language for manipulating text.
You don’t need to learn everything at once.
Start with:
w b 0 $ dd cw ci" yy p u . / n
Use them every day.
After a while, you’ll find yourself making changes in a few keystrokes that previously required a mouse, multiple selections, and a lot of backspacing.




Kudos to the you for compiling such a comprehensive guide. Keep up the excellent work!