[Home] [Downloads] [Search] [Help/forum]

Nick's guide to vi(m)

Author: Nick Gammon

Date written: 2nd February 2004
Amended: Friday 29th September 2017

Permission is granted to link to, or reproduce, this page, providing the original credit (above) is retained.
The original version may be found at http://www.gammon.com.au/smaug/vi.htm

vi (VIsual editor) is the standard Unix text editor. It comes with Unix, Linux, and Cygwin (if you are using Windows).

If you are going to use vi I would obtain a copy of vim (vi iMproved) which may well be installed as standard. For instance, with Cygwin vim is standard. To test this, just type "vi" on its own at a command prompt. If you see a page about "VIM - Vi IMproved" then you have vim.

This page will attempt to cover the common commands that I use (as a programmer) - vi(m) is actually much more powerful (and complex) than I will show here, but the basics should be all you need. Many of the things described (like visual mode) are specific to vim, but the basics should apply to both.

Topics on this page in alphabetic order

Why use vi?

When I first tried using vi I thought that you could not have a more obscure and difficult-to-use text editor, but I found that after memorising half-a-dozen commands that it was really quite simple to use. And, quite powerful. For example, you can do something like "find all lines with 'swordfish' in them, and for those lines only, change 'cat' to 'dog'". Try doing that with your normal editor!

The other reason is you can usually find vi on almost any Unix installation. If you get used to "my favourite editor" - whatever that is - and connect to a different site for troubleshooting, you may well find it is not installed, or only runs under Xwindows, or some other such restriction.

Further, you can do quite fancy things (see below) like do a "make" from inside vi, and then with a single keystroke go to each error message (even in different files), with the cursor being placed on the line in error, so you can fix it. This is quite a time-saver. Similarly with doing "grep" on a group of files.

The basics

If you start doing something and change your mind you can generally press Ctrl+C to cancel it.

Edit a file, look at it, stop editing

Edit a file from command prompt vi <filename>
Edit a file from command prompt for reading only vi -R <filename>
Edit a file from within vi :e <filename>
Edit a new file from within vi, discard changes to current file :e! <filename>
Reload current file, discarding changes :e!
Go forwards a page Ctrl+F (or PgDn)
Go backwards a page Ctrl+B (or PgUp)
Move around single lines or characters Arrow keys
Save changes :w
Save changes and override protected (read-only) files :w!
Save changes and exit vi ZZ
Quit :q
Quit and discard changes :q!
Get general help :help
Get help on a command (eg. :set) :help set


  1. Whether keys like PgUp and PgDn work will depend on your keymappings. I find recently that they tend to work without needing to make any changes. In some cases you may need to type "vim (file)" at the command prompt rather than "vi (file)" if both are installed. Otherwise you may set up an alias (at your shell prompt) to equate vi to vim.
  2. Any command starting with these characters:
    • : (colon) - starts a command sequence
    • / (slash) - starts a forwards search
    • ? (question mark) - starts a backwards search
    needs you to press <Enter> to execute them. Until you have done that you can backspace and make corrections.

    These commands are echoed on the bottom line of the screen, so you can see what you are typing. If you have started typing one of those, you see the command being echoed, and change your mind, press Ctrl+C to cancel the command.

Simple example

Let's edit comm.c and then exit ...

vi -R comm.c
(PgDn to look at file)

If you are experimenting then it might be wise to either edit a file you don't care about (eg. a copy) or use the -R option (read-only).

Alternatively, set read-only mode once you have edited the file:

Set read-only mode :set ro

Go to lines, find matching text (search)

Go to line 1234 (do not see typing) 1234G
Go to line 1234 (see typing) :1234
Go to start of file 1G
Go to end of file G
Find (forwards) a line containing "swordfish" /swordfish
Find (forwards) a line using a regular expression /you see .* here
Repeat last search n
Repeat last search in opposite direction N
Search for word under cursor *
Search for word under cursor (without \< ... \> around it) g*
Search backwards for word under cursor #
Search backwards for word under cursor (without \< ... \> around it) g#
Find (backwards) a line containing "swordfish" ?swordfish
Find (backwards) a line using a regular expression ?you see .* here
Search case insensitive (Ignore Case) :set ic
Search with case sensitivity :set noic
Wrap searches back to start of file :set wrapscan
Do not wrap searches :set nowrapscan

Notes - these are probably the most frequent things I do. 'Go to line number', especially if you have a compiler error which gives a line number is very handy. Type the line number directly followed by "G", and you are taken there. Or, if you don't know the line, type "/" followed by a word or regular expression you are looking for. The second way of going to a line number (:1234) is probably easier to use because you can see the number as you type it. If you type "1234G" the number (1234) is not echoed to the screen as you type.

Highlighting - searching with "/" or "?" normally highlights the found word. Sometimes this can be quite annoying, especially if you have searched for something which occurs frequently, like a space. You can turn this off:

:hi clear search

Case-sensitivity - using ":set ic" lets you search with or without matching the exact case of the word you are searching for (eg. if you search for "dog" do you want to match "DOG"?).

Simple example

Let's edit comm.c and go to line 5522. Then find "const".

vi comm.c

Line numbers

Sometimes it is handy to know what line you are at, or what each line number is.

Show line numbers on the left :set nu
Do not show line numbers on the left :set nonu
Show the current line number :.=
Show total lines in file :=
Show file name, total lines, and current line number Ctrl+G
Show line number of first matching pattern :/pattern/=

Notes - showing lines numbers is particularly useful when you are relating things like error messages (or instructions) to a line number. Also the Ctrl+G trick is useful to remind yourself of what file you are editing.

Simple example

Let's edit comm.c, show line numbers, find the first line with "const" in it (line 70) and go to it:

vi comm.c
:set nu

Changing text

OK, we can move around the file and find things. Let's start changing stuff ...

Undoing things

When you start going into "change things" mode you will probably need to undo your mistakes. Two useful commands:

Undo last change u
Undo all changes on current line U

If things get out of hand, remember:

Quit editor without saving changes :q!
Reload current file, discarding changes :e!

Insert text

All of the changing commands (except "replace next character") go into "insert mode" (usually shown by "-- INSERT --" or "-- REPLACE --" at the bottom of the screen). To exit from Insert Mode, press the Esc key.

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

The last two are the letter "oh" not a zero. I use the "O" and "o" commands quite a bit to start entering a new line above or below where the cursor currently is.

Change existing text

Replace next character r
Type over following characters R
Replace to end of line C

Note - the "r" command is useful if you just want to make a minor correction (eg. change "A" to "B"). This does not go into Insert Mode, so you don't need to then cancel Insert Mode. To change the character under the cursor to a "B" you would just type "rB".

Delete text

Delete character under cursor x
Delete character to left of cursor X
Delete to end of line D
Delete entire line dd

These are your basic deletion commands. "x" to scrub out the character under the cursor, "dd" to delete the entire line.

Advanced deletion

Delete next 5 lines 5dd
Delete to end of line d$
Delete to start of line d0
Delete to word "swordfish" d/swordfish
Delete to the letter "x" dfx
Delete lines 10 to 20 :10,20d
Delete current line and another 5 lines :.,+5d
Delete all lines :%d
Delete current word dw
Find line containing pattern, delete it :/pattern/d
Find line containing "dog", delete until line containing "cat" :/dog/,/cat/d
Delete from current line to line containing "foo" :.,/foo/d

Copying, cutting and pasting

If you delete some text using the deletion commands described above you have "cut" the text. However it is saved in an internal buffer and can be pasted somewhere else. Simply move the cursor to where you want it and:

Paste after cursor p
Paste before cursor P

vi calls copying "yanking", and thus uses the letter Y.

To copy text without deleting it you need to "yank" it. The yank commands are similar to the deletion commands, like this:

Yank to end of line y$
Yank to start of line y0
Yank to word "swordfish" y/swordfish
Yank to letter "g" yfg
Yank entire line Y
Yank lines 5 to 10 5,10y

After yanking you can paste as described above (or there is no point to yanking in the first place).

Advanced movement commands

Go forwards a word w
Go backwards a word b
Go to end of word e
Go to start of line 0
Go to end of line $
Go to top of screen H
Go to middle of screen M
Go to bottom of screen L
Go (forwards) to letter "x" on current line fx
Go (backwards) to letter "x" on current line Fx
Go to next occurrence of word under cursor *
Go to previous occurrence of word under cursor #
Find a control character (eg. Tab) /(Ctrl+V)(Tab)
Go backwards a sentence (
Go forwards a sentence )
Go backwards a paragraph {
Go forwards a paragraph }

The command "go to start of line" is a zero, not an "oh". You can use Ctrl+V in insert or command mode to literally insert the next character.

Repeat counts

Most commands have a "repeat count" that you can optionally type first. To do a repeat count just type the number before the command. It will not be echoed, so type carefully!

For example:

Delete 5 lines 5dd
Delete 5 characters 5x
Delete 5 words 5dw
Replace next 5 characters 5r
Yank (copy) next 7 lines 7Y
Go to line 1000 1000G
Paste copy buffer 10 times 10p
Insert 40 hyphens 40i-<Esc>
Insert the line "swordfish" 10 times 10oswordfish<Esc>
Find the 5th occurrence of "swordfish" 5/swordfish
Repeat last command @:

In the above examples <Esc> means press the Esc key.

Splitting and joining lines

Split a line (insert a return) i<Enter><Esc>
Join two lines (current and next) J
Join next 10 lines 10J
Join lines 10 to 20 :10,20j

Splitting is basically breaking a line into two by inserting a newline. Joining is reversing that process by removing the newline.

Search and replace

Change "nick" to "fred" on current line :s/nick/fred/
Repeat last search n
Search for word under cursor *
Repeat last search and replace :s
Repeat last search and replace (shorthand) - discards flags &
Repeat last search and replace - keeps flags :&&
Repeat last replace with most recent search :~
Change "nick" to "fred" on the next 5 lines :.,+4 s/nick/fred/
Change "nick" to "fred" on lines 100 to 200, all occurrences :100,200 s/nick/fred/g
Capitalise every word in the entire file :% s/\<./\u&/g
Insert ">" at the start of every line :% s/^/>/
Append "// nick" at the end of every line :% s;$;// nick;
Change "foo" to "bar" globally on every line with confirmation :% s/foo/bar/gc

Special characters for line sequences:

Things you can replace

Search and replace flags

Note that the character "/" for the search delimiter can be any single-byte excepting letters, numbers, "\", double-quote, or "|".

Applying commands to certain lines

You can use the ":g" (global) command to find matching lines (using a regular expression) and then apply a command to those lines. For example:

Find lines containing "fruit" and change "apple" to "orange" on them :g/fruit/s/apple/orange/g
Delete all blank lines :g/^$/d
Find lines NOT containing "nick", append "oops" to them :g! /nick/normal A oops

The third example above shows you you can use the "normal" command inside a command, to tell vi to use a normal character (in this case A for append) as part of a command.

Shell and filter commands

List directory :! ls
See processes :! ps
Sort lines 20 to 30 :20,30 ! sort
Sort entire file !G sort
Translate next sentence to upper case !) tr '[a-z]' '[A-Z]'
Word count file (save first) :!wc %
Look up manual entry for strstr :!man strstr
Insert "ls" command output into window :r !ls


Tags let you go to the definition of a function (in C or C++) without having to scan lots of source files (with grep) and work out which ones contain the function and which merely refer to it.

First, make a tag file, like this:

ctags *.c *.cpp *.h

(In recent versions of Linux I have had to use gctags instead of ctags).

This should produce a file "tags" in the current directory.

Now you can go straight to a function, without knowing which file it is in, like this:

vi -t game_loop

Once inside vi you can put the cursor on a word and go to its definition:

Go to function under cursor Ctrl+]
Go back Ctrl+T
Go to function xyz :tag xyz

Automating things

Compiling from within vi and going to errors

You can save your changes, run "make" to compile, and view errors, very easily ...

Save file :w
Run "make" :make
Go to next error :cn
Go to previous error :cp

This is fabulously powerful. It lets you skim through all your errors, with vi opening the right file and positioning the cursor on the line in error.

See below for how to map actions (like ":cn") to function keys to speed up the process.

Mapping actions to function keys

Map the action :cnext to <F6> :map <f6> :cnext<cr>
Map the action :cprevious to <F7> :map <f7> :cprevious<cr>
Map the action :make to <F8> :map <f8> :make<cr>
Map the action :close to <F12> :map <f12> :close<cr>

After entering the above commands you could compile by simply hitting F8, then look at each error by hitting F6.

More useful tips for programmers

Go to definition of word under cursor gd
Go to global definition gD
Find matching bracket, brace, #if, #endif %
Do a grep :grep foo *.c
After grep, go to next occurrence :cn
Get a file (eg. an #include file) whose name is under cursor gf
Auto complete (in insert mode) - match forwards Ctrl+X Ctrl+N
Auto complete (in insert mode) - match previous Ctrl+X Ctrl+P
Make an abbreviation (eg. cca = "const char *") :ab cca const char *
Turn syntax colouring on :syntax on
Turn syntax colouring off :syntax off
Execute any shell command :! command
Indent selected lines with C-style indenting =

For formatting of C code there are also other options you can use like "autoindent", "smartindent", "cindent", and "indentexpr". (Use :help (topic) to see more about those options). You can turn these on (eg. :set cindent) to automatically indent your coding as you type. Also, in conjunction with syntax colouring, you can see if you have made a syntax error (eg. not closed a quote, left off a bracket), as the syntax colouring algorithm will highlight in red sequences that do not seem correct.

Spellcheck file

Save file first :w!
Spell check it :! ispell %
Edit fixed file :e %

Tab management

Tabs can be annoying in source files, as they do not necessarily line up when you use different value tab stops. You can manage them in vi like this:

Set tabs to every 4 characters :set ts=4
Convert tabs to spaces in future :set et
Do not expand tabs :set noet
Fix existing tabs (convert to spaces) :%retab
Show tabs visually, and end-of-lines :set list
Do not show tabs and end-of-lines :set nolist

Visual mode

vi can be a bit difficult to follow when you are trying to do something to a block of lines (for example, do I want line 8843 through to 8903 or 8904?), so vim has a "visual mode" where you can actually see lines highlighted in inverse.

First, "mark" a block of lines (or characters) by going to the start of the block, and then using one of the following:

Character mode v
Line mode V
Block mode Ctrl+V
Re-mark previous block gv

The differences are:

Then use the cursor movement commands (search, arrow, go to line, whatever) to mark the other end of the block, and either:

Do some command (see below)
Cancel visual mode Esc
Go to other end of block o

Other ways of establishing a visual block

A word (with white space) vaw
Inner word viw
A WORD (with white space) vaW
Inner WORD viW
A sentence (with white space) vas
Inner sentence vis
A paragraph (with white space) vap
Inner paragraph vip
A ( ... ) block (includes brackets) vab
Inner ( ... ) block vib
A { ... } block (includes braces) vaB
Inner { ... } block viB

A "word" is a sequence of letters, numbers, underscores. A "WORD" is a sequence that is terminated by spaces. The difference would apply in cases like a(b) - if the cursor is on "a" a "word" is "a" however a "WORD" is "a(b)".

Here is an example, from C source code. Say you have the following code, and you want to select the code inside the inner { ... } characters. Put the cursor in the middle (eg. on CON_EDITING) and type "viB" and the "inner block" (text in bold) will be highlighted.

if ( d->pagepoint )
  if ( !pager_output(d) )
    if ( d->character
    && ( d->connected == CON_PLAYING
    ||   d->connected == CON_EDITING ) )
        save_char_obj( d->character );
    d->outtop = 0;
    close_socket(d, FALSE);

Here is another method of selecting a visual block of C code. Say we have the following code and we want to highlight everything inside the "while" loop. Put the cursor on the first "{" and type "v%". That will go into visual mode and move to the end of the block. The highlighted code will be in bold.

while ( usecDelta >= 1000000 )
    usecDelta -= 1000000;
    secDelta  += 1;

Visual mode commands

See below for meanings of notes in brackets.

Switch case ~
Delete d
Change (4) c
Yank y
Shift right (4) >
Shift left (4) <
Filter through external command (1) !
Filter through 'equalprg' option command (1) =
Format lines to 'textwidth' length (1) gq

You can also do the following on the selected block:

Start ex command for highlighted lines (1) :
Change (4) r
Change s
Change (2)(4) C
Change (2) S
Change (2) R
Delete x
Delete (3) D
Delete (2) X
Yank (2) Y
Join (1) J
Make uppercase U
Make lowercase u
Find tag Ctrl+]
Block insert I
Block append A


  1. Always whole lines
  2. Whole lines when not using CTRL-V.
  3. Whole lines when not using CTRL-V, delete until the end of the line when using CTRL-V.
  4. When using CTRL-V operates on the block only.

An example of visual mode?

OK, let's say we have a visual block highlighted. Try these:

Delete it d
Copy it Y
Change "apple" to "orange" in the block :s/apple/orange/g
Turn into C++ comments :s.^.//.
Turn into C comments :s-^.*$-/* & */-

Marking your work

If you need to jump backwards and forwards between a couple of places you can "mark" them ...

Mark current position as "x" mx
Go to position "x" `x
Show list of known marks :marks

That character before the "x" is a back-quote - on my keyboard on the top-left corner, under the tilde (~) symbol. Marks can be in a different file to the current one.

Recording commands

Finally, let's do an example of recording commands for repeating later.

Record a sequence q(letter)(commands)q
Play back sequence @(letter)
See what is in registers :reg

You record a sequence into a lower-case register (a-z), eg.


The command above (starting and ending with "q") records into register "a" the sequence ":s/fish/chips/".

Then whenever you want to repeat that command you can type "@a".

Example of recording

Whilst writing this page I wanted to convert every second sequence of:

<td> (something) </td>


<td><code><font size=2> (something) </font></code></td>

Doing a "find and replace" would have been tedious, as I would have had to skip every second item found. I was able to do it quite quickly by recording a macro. To do this I typed:

:s/<td>/<td><code><font size=2>/

The sequence above did the following:

  1. Start recording (q) under register "a"
  2. Search for the second occurence of <td> (hence the leading "2" on the line)
  3. Change "<td>" to "<td><code><font size=2>"
  4. On the same line change "</td>" to "</font></code></td>". I used a $ as the search delimiter because the character "/" was in the text to be searched for.
  5. Go to the end of the current line ($) so the next search would begin at the next <td>
  6. Stop recording (q)

Then I moved to the start of the file (1G), turned search wrapping off (:set nowrapscan) and typed "999@a". This executed macro "a" 999 times. In fact, it stopped before 999 times because the search failed after it got to the end of file.

Setting up your personal favourite settings

If you have some personal favourite settings like:

you can have them processed automatically by putting them into a file named ".vimrc" in your home directory (see ":help vimrc" inside vim for more details).

For example, your .vimrc file might have in it:

set ts=4   " tab stops every 4 characters
set expandtab  " tabs to spaces

map <f6> :cnext<cr>   " next error after a make or grep
map <f7> :cprevious<cr> " previous error
map <f12> :close<cr>    " close current window (eg. help)

syntax on  " syntax colouring on

hi clear search  " do not highlight searched-for words

set mouse=a  " enable all mouse actions

Written by Nick Gammon - 5K

Comments to Gammon Software support

[Best viewed with any browser - 2K]    [Hosted at HostDash]

Page updated on Friday 29th September 2017