This file is based on the original text version. It was first written for Beginning Linux, an online book written by members of KPLUG. Also, a version of this was published on snipe.net before I converted this primer to HTML.

This work is placed in the public domain, and I abandon all copyright interest in it. Do with it what you will.

Abstract

vi (short for ‘visual’, and pronounced vee-eye) is a screen-oriented editing program used by many Unix users and, in particular, programmers. Regular users of vi find it a very convenient editing program, but it does take learning, and at first that will look unintuitive. Hopefully this guide is but one step towards hopping over that hurdle.

Basic editing

Help! How do I get out of this confounded program?

In a word, :q!

vi has possibly one of the most unintuitive interfaces, and for the user who's used to graphical editors, the first thing they want to do is to quit and return to safety. :-) I heard stories of users who quit vi by rebooting their system!

Of course, that doesn't help get your work done. The rest of this primer will, I hope, give you a slightly bigger picture. The sections below feature commands you will want to type—these I've marked with -> on the left hand side. I've also marked examples with *.

Okay, so what useful things can I do other than quit?

-> i

Most users want to, of course, be able to add stuff to the file they're editing (that being one of the main uses of an editor). You can't just type straight away—when you start vi, you're in what may be called ‘command mode’ where you enter commands.

Type the letter i (for insert), in lowercase. This tells the editor that you want to insert text into your file (more accurately the ‘editing buffer’ since changes are not written back to the file unless explicitly told to; see the section on dealing with files). Just start typing from here on.

How do I get back into command mode?

-> <Esc>

When you're in insert mode, hitting the ‘escape’ key will get you back into command mode. Think of it as an escape from insert mode.

Help! The arrow keys don't work!

No, on some systems the arrow keys don't work. If you're currently in insert mode, get back into command mode (see above), then hit the keys corresponding to the direction you wish to move:

        k       Hit k to go up,
        |       h to go left,
    h <-+-> l   l to go right,
        |       and j to go down.
        j

Remember to get back into insert mode before you start entering text again.

How do I add text to the end of a line?

-> a

You'll probably realise that the direction keys will not bring the cursor beyond the last character in the line. Typing the letter a (for append) will put you in insert mode just to the right of the cursor.

If you don't want to have to move to the end of the line to add something to the end of the line, type A in capitals. This will get you to the end of the current line, no matter where in the line you were.

But moving a character at a time is too slow!

-> w
-> b

Typing w in command mode moves you to the start of the next word, and b does the reverse.

-> ^
-> $

Typing ^ gets you to the beginning of the line, and $ to the end. If you are familiar with regular expressions (outside the scope of this document) you'll find them easy to remember.

-> <Ctrl>U
-> <Ctrl>D

Ctrl-U and Ctrl-D move about half a screen up or down, respectively.

-> :1
-> :$

:1 gets you to the first line in the buffer. (It should be obvious by now that you can replace 1 with any line number you care to choose.) :$ gets you to the last line in the buffer.

-> I
-> A

If you're inserting text at the beginning or end of lines, the command I is similar to ^i (insert at beginning of line), and A is similar to $a (append at end of line).

I can't delete text in insert mode!

-> x
-> X

In insert mode, you can only delete text that you've typed in the current line, in the current insertion. That is, if you hit the escape key and re-enter insert mode, you can't delete what you've typed previously by hitting the backspace key.

One way to delete text, a character at a time, is to get into command mode and type either x or X—the lower case version deletes the character at the cursor (and behaves similarly to the ‘delete’ key in graphical editors) and the upper case one deletes the character just before the cursor (and behaves similarly to the ‘backspace’ key in graphical editors).

-> dmotion

Typing the letter d, followed by a motion command (like h or l, or more usefully w) deletes text from the cursor to the target of the motion command. For example, dw deletes from the cursor to the start of the next word.

-> D

This command deletes to the end of the line, and is similar to d$.

-> dd
-> :d

Both of these commands delete the whole line. To delete a whole bunch of text I just hold down the d key until I'm satisfied. :-)

Joining/splitting.

-> :j

The :j command joins the current line with the next. A single space is added to the end of the first line, unless the first line ended with a full-stop, in which case two spaces are added.

You split a line the conventional way—go into insert mode, and hit the return key.

Substituting text.

Yeah, to replace text you can just remove and then insert, but there are faster ways to do things.

-> s

Replaces the character under the cursor. More useful than it looks, when you read two sections down. :-)

-> S

Replaces the whole line.

-> cmotion

Replaces text from the current point to the target of a motion, similar to the d command, but replacing instead of deleting.

-> C

Replaces from the current point to the end of the line, similar to c$.

-> :s/from/to/

Replaces the first instance of from in the line to to. from and to can both be normal plain text (e.g., :s/1998/1999/ replaces the first 1998 in the line to 1999) but from is more accurately described as a regular expression (which once again is outside the scope of the document).

-> :s/from/to/g

As above, but replaces all instances and not just the first.

I'm looking for a needle in a haystack—help!

-> /pattern

This will search from the current cursor position, through to the end of the buffer, for pattern which is a regular expression (again, in most cases you can just type in plain text).

-> ?pattern

Searches backwards from the cursor position to the beginning of the buffer for the pattern.

-> n

Repeats the last search command, with the same pattern. If you last used a /, the search will continue forward; if you last used a ?, then it proceeds backwards.

This command will not work if you have not used / or ? in the current session yet.

-> N

Similar to n, but reverses the direction of the search.

The commands mentioned in this section are all motion commands, and may be used wherever motion is called for.

But some of these commands only affect one character!

Most of the commands above that have no colons can have a number typed before it for repeating the action. Examples:

* 8w
advances the cursor 8 words forward.
* 4s
replaces the 4 characters from the cursor onwards.
* 3i
inserts whatever text you type 3 times. Useful if you need to repeat something many times.
* 10dd
deletes 10 lines from the current line down.

Remember—the commands with colons don't behave that way.

So how do I repeat colon commands?

(This section is slightly more technical—you may wish to skip it.)

The colon commands (or more precisely called ‘ex commands’, because they are used in the ex(1) editor) work with the notion of ‘ranges’, which come just after the colon. Ranges are best described by examples.

The :1 and :$ commands mentioned earlier are not really commands, but line specifications, which stand for the first line and the last line respectively.

In addition, the dot, ., stands for the current line. You can offset this by a certain number of lines by using + or - followed by a number. For example, $-3 refers to three lines up from the end, and .+5 refers to the fifth line down from the current one.

A range is specified by two line specifications separated by a comma. For example, 2,5 means between lines 2 and 5, including lines 2 and 5.

The percent symbol, %, is a shortcut for 1,$.

And now, some real-life examples. :-)

* :%d
zaps the whole buffer.
* :.+1,$-4d
deletes everything from the next line down to the end of the buffer, except the last four lines. If your email signature is, say, four lines long, this is a convenient way to zap your message without zapping your signature with it.
* :%s/foo/bar/g
replaces all instances of foo with bar.
* :.,.+3j
joins the current line with the three following lines.

How do I repeat what I just did?

-> .

The dot command, ., repeats the last command you did that actually changed the buffer. Movement commands don't count.

Oops—I've made some fatally awful (or awfully fatal) mistake!

-> u

The standard way to undo the last action. Note that many implementations of vi only has a single level of undo, so hitting u twice is the same as doing nothing at all (it just undid your undo).

The Berkeley vi implementation, nvi, allows multiple level undo by typing dots (it repeats your undo). Most cabbage vi implementations, though, repeat your last command (before your undo) if you type dots.

Playing with files

How do I save to a file?

-> :w
-> :w filename

The :w command saves the current buffer (analogous to ‘save’ in a graphical editor). If you specify filename, the contents of the buffer is written to a different file.

If you specify a filename, you normally won't be able to specify an already-existing file. If you must overwrite that file anyway, then add a ! after the :w.

* :w! foo.bar
saves the buffer to foo.bar whether or not foo.bar already exists.

How do I edit a different file?

-> :e filename
-> :e!

The :e command either reloads the current file, or the file specified if filename is given. If your buffer has been modified and not yet saved, you won't be able to reload the buffer unless you add a ! after the e.

* :e! foo.bar
start editing foo.bar, discarding changes currently made to the buffer.

How do I embed another file?

-> :r filename

Reads the contents of filename and embeds it into the current buffer.

-> :r !command

Executes command and embeds into the buffer the output generated by the command.

* :r !fortune -s
puts a short fortune into your buffer—one way of making email signatures.

Gettin' outta here.

-> :wq
-> ZZ

Both of these do pretty much the same thing—save changes made to the buffer and exit vi.

-> :q!

Quits vi, discarding all changes made to the editing buffer.