A VI Primer: VI Is A Simple, Visual Editor. It Is Very Fast, Easy To Use, and Available On Virtually Every UNIX
A VI Primer: VI Is A Simple, Visual Editor. It Is Very Fast, Easy To Use, and Available On Virtually Every UNIX
A VI Primer: VI Is A Simple, Visual Editor. It Is Very Fast, Easy To Use, and Available On Virtually Every UNIX
66 UNIX Tools
vi Primer
A vi Primer
vi is a simple, visual editor. It is very fast, easy to use, and available on virtually every UNIX
system. Although the set of commands is very cryptic, I learned it, as have thousands of others,
which is proof that you can learn it too.
Notation
In the rest of these notes,
1. <CR> will denote the carriage return character obtained by pressing the Enter key on the
keyboard and that we normally call the newline character.
2. <SP> will denote the space character, obtained by pressing the space bar. It will sometimes
be necessary to represent this character as an underline "_" instead of <SP>.
3. <ESC> will represent the character obtained by pressing the escape key.
4. In general, angle brackets <> around a word represents the character(s) described by the
word, so for example, <positive integer> will mean any positive integer, and <char> will
mean any single character.
Basics
1.
Starting vi. That is easy. To edit a file named myfile, at the command prompt, type
vi myfile
2.
COMMAND
MODE
INSERT
MODE
Escape key
Enter key
:,\,?,!
LAST LINE
MODE
1 of 13
What you can do in each state and how you can change vi's state is discussed below.
3.
vi is CASE-SENSITIVE: everything you type must be in the correct case. If you read that
"w" advances to the first character of the next word in the edited file (which it does) then
you must use "w", not "W". The uppercase letter will do something else.
4.
vi makes a copy of the file in a work buffer and places this in a temporary location (usually
in /tmp or /var/tmp) often called the scratch directory in UNIX. On some UNIX
systems, this is a world-readable file, in which case you should not edit documents you do
not want people to see using vi. You can edit them on a non-timeshared, non-networked
computer (your home computer) instead and upload them to the UNIX system. You can
also use vi in a secure mode, in which it encrypts the work buffer. See the man page for vi
for details look up the -x option. First check whether the system is making the work
buffers world-readable by running ls l on the scratch directory. Note: if you do use the x
option for vi, no other program will be able to read the file, because vi will encrypt the
saved file also. To decrypt the file, you will need to use the crypt command, as in:
crypt your_encryption_key < file_to_decrypt > cleartext_file
5.
6.
The start of a line is the leftmost NON-WHITE-SPACE character. Commands that move
the cursor to the start of a line or modify the start of a line act on this first non-white-space
character. If a line starts with leading blanks or tabs, these are not treated as part of the line
when referring to the "start".
7.
The end of a line is the last character before the <CR>, even if it is a white space character.
8.
vi 's internal help command is the only way to get help. Type :help<CR> while in vi.
2 of 13
3 of 13
Key Sequence(s)
j, Down Arrow, ^N
k, Up Arrow, ^P
h, Backspace, Left Arrow
l, Space Bar, Right Arrow
<CR>, +, ^N
<line number>G
G
0 (zero)
^, Home Key
$, End Key
<position as a number>
An integer replication factor can be prefixed to any command, not just navigation. For example,
3j means move down 3 lines. This integer is called a multiplier in vi.
The following are movements based on the word structure of the text.
.
Next word ignoring punctuation chars
w
Next word including punctuation chars
W
Previous word excluding punctuation chars
b
Previous word including punctuation chars
B
End of next word excluding punctuation chars
e
End of next word including punctuation chars
E
The definition of a word is somewhat complex. A word is a sequence of one or more word
characters, but punctuation complicates it a little. If you want to skip across white space, use W.
There are also commands to move across sentences and paragraphs:
Move to the start of the next sentence
Move to the start of the previous sentence
Move to the start of the next paragraph
Move to the start of the previous paragraph
Move right to the next matching character
Move left to the previous matching character
)
(
}
{
f<character>
F<character>
4 of 13
t<character>
T<character>
;
,
Key Sequence
a
A
i
I
o
O
R
cw
c$
ct
cc
>
<
s/<pattern>/<pattern/<flags>
This last operator, the substitute operator, is the single most important operator in vi. It is
described in the section below entitled About the Substitute Operator.
If you want to replace a single character, you type
and this will return to COMMAND MODE.
Deleting Text
Delete character to the right of the cursor
Delete character to the left of cursor
Delete current line
Delete current word
Delete to the end of the current word
(does not delete delimiter)
Delete to end of sentence, paragraph, line, etc
depending on symbol after d
5 of 13
r<character>
x
X
dd
dw
de
d), d}, d$ etc.
^L
~
J
p
P
There are ways to copy text into the buffers without deleting it. This is called yanking in vi.
Copy word
Copy to the end of line
Copy line
yw
y$
yy
Key Sequence
w
w <file>
w! <file>
q
wq
q!
r <file>
f
6 of 13
k<char>
In addition, in colon mode there are operators that can act on a range of lines. A range is of the
form
<line expression>, <line expression>
where <line expression> is either a line number, a quote followed by a line mark, or a regular
expression, described below. When an expression is ambiguous, meaning that it might match
more than one line, it is taken to be the first of the matched lines. This can happen with regular
expressions, since many lines might match an expression.
Examples of Range Expressions
Range
Meaning
1,5
lines 1 through 5
1,$
all lines in file
'x, $
lines from the one marked x to the last line
'a, 'b
lines from the one marked a to the one marked b
/aa*/,/bb*/
all lines from the first occurrence of a line
matching pattern aa* to the first occurrence of a line matching bb*
In colon mode, you can use some of the operators already mentioned above, as well as some that
can only be used in colon mode. The most powerful of colon mode operators is the substitute
operator, s. To understand how to use it, you need to know about patterns. Therefore, I will
delay discussing the substitute operator until after I present patterns to you. The operators that
can be used in colon mode are:
delete
yank
right-shift
left-shift
substitute
pattern/flags
Examples
:1,10d
:6,$y
:1,$>
d
y
>
<
<range>
s/target-pattern/replacement-
In addition, colon mode has the move and copy operators, m and co. These are a little tricky
because the source range cannot overlap the target line. In other words, you cannot move lines 1
through 10 to line 5, or copy lines 1 through 10 to line 5.
7 of 13
<range-expression>m<line>
<range-expression>co<line>
Searching
There is a way to search for patterns in the file using a pattern matching language much richer
and more complex than the ones you will find in applications like Microsoft Word. The
characters / and ? are pattern search operators. The / operator searches downward and wraps
around to the top and the ? searches up and wraps around to the bottom. In short,
Search downward for pattern
Search upward for pattern
Repeat last search in the same direction
Repeat last search in the opposite direction
/<pattern>
?<pattern>
n
N
About Patterns
A pattern can be a simple string, or it can be a regular expression constructed by the rules
described in the regexp man page. Type "man regexp" on the UNIX system to get the full
story. This is only a brief synopsis of patterns. There are many more ways to construct them
than are shown here.
1. Certain characters are special characters and have special meanings. These are period (.),
asterisk (*) , left square bracket ([), backslash (\), caret (^), dollar-sign ($).
2. All other characters are one-character regular expressions.
3. The period (.) is a one-character regular expression that matches any character except
NEWLINE.
4. The special characters can be matched by escaping them with a backslash: \$ matches $ and
\[ matches [ for example.
5. Let p and q represent patterns (regular expressions). Then the following are also patterns
Pattern
pq
p$
^p
\(p\)
[<list_of_chars>]
[c1-c2]
[^<char_range>]
Meaning
matches any string that matches p followed by any
string that matches q
matches p only when anchored at the end of a line
matches p only at the beginning of a line
matches p and saves the matching string in the next
free register
matches a single character in the list
matches a single character in the range c1 to c2
where c1 precedes c2 in ASCII ordering
matches any single char except those in the
specified range
8 of 13
Pattern
c*
c\{n,m\}
c\{n,\}
c\{,m\}
Meaning
matches 0 or more consecutive c's
match between n and m consecutive c's
match n or more c's
match up to m consecutive c's
This is just a start. I suggest you read the man page for regexp, since this is the most powerful
part of vi, and these regular expressions also form the pattern matching language of sed, awk, and
other tools.
About the Substitute Operator
The substitute operator, once again, is used with the syntax,
s/target-pattern/replacement-pattern/
or
s/target-pattern/replacement-pattern/flags
or
<range expression> s/target-pattern/replacement-pattern/flags
in LAST-LINE MODE (meaning you typed a colon first.). If you omit <range expression>
in LAST-LINE MODE, it applies the substitution only to the current line.
The substitute operator will search for the first occurrence in each line of the range or the current
line only in COMMAND MODE and will replace the longest matching occurrence with the
replacement pattern. If you want all occurrences on the line to be replaced, put a "g" where it
says flags above. "g" means global.
Examples
Suppose the current line is
abcdeabcde
meeemeeemeee
12345123451234512345
Command
Resulting Line
s/abcde/xxxxx/
xxxxxabcde
meeemeeemeee
12345123451234512345
s/abcde/xxxxx/g
xxxxxxxxxx
meeemeeemeee
12345123451234512345
s/me*/X/
abcdeabcde
Xmeeemeee
s/me*/X/g
abcdeabcde
XXX
s/\(m.*\)<SP><SP>*/\1/
abcdeabcde
meeemeeemeee12345123451234512345
s/\(.....\)\1//
meeemeeemeee
s/\(.....\)\1//g
meeemeeemeee
12345123451234512345
12345123451234512345
12345123451234512345
9 of 13
Comments
The first two are easy to follow. Adding the g flag makes the substitute apply to all occurrences
of abcde. The third looks for a string consisting of 5 letters followed by the exact same 5 letters
and deletes the first such occurrence. The fourth does this to all such strings on the line.
Useful or Enlightening Patterns
Some patterns arise often. Here are some I find most useful
[a-z][a-z]*
a lowercase word
[A-Z][a-z]*
a capitalized word
[a-z-][a-z-]*
a lowercase word with hyphens, like last-line
In the above example, the last hyphen is not part of a range; it is the literal hyphen character.
UNIX regular expressions allow the hyphen to appear as the first or last character in the []
operator without having to be escaped. So the next one is equivalent.
[-a-z][-a-z]*
[]]
[\]]
[1-9][0-9]*
[<SP>][<SP>]*
[a-zA-Z_][0-9A-Za-z_]*
\([a-z][a-z]*\)\1
^$
[^a-zA-Z0-9][^a-zA-Z0-9]*
Example 1
Suppose I have a file consisting of lines of the form
Albert Sionov
Andrzej Such
Jacek Szulc
Khai Tran
Karl Treen
asionov
shiva
asuch
shiva
jszulc
hejira
ktran
hejira
ktreen
hejira
This is a list of first name, last name, user-name, host-name records. The amount of white space
varies from one line to another.
Suppose I want to convert it to the form
10 of 13
asionov@shiva
asuch@shiva
jszulc@hejira
ktran@hejira
ktreen@hejira
Albert Sionov
Andrzej Such
Jacek Szulc
Khai Tran
Karl Treen
in which the email address is separated from the first name, last name by a tab, and the first name
and last name are separated by a space character. I can do this in several steps.
First, I start by deleting leading white space:
:1,$s/^ [ ]*//
The target pattern is a sequence of one or more space characters anchored to the start of the line.
The replacement pattern is empty. The effect is to delete all leading white space:
Albert Sionov
Andrzej Such
Jacek Szulc
Khai Tran
Karl Treen
asionov
asuch
jszulc
ktran
ktreen
shiva
shiva
hejira
hejira
hejira
I then replace the white space between the username and the last word on the line by a "@".
Since I want this to work for any last word on the line, I use the pattern [a-z][a-z]* to represent a
sequence of one or more lowercase letters. To anchor to the end, I can use [a-z][a-z]*$. So I start
to write:
:1,$s/ [ ]*[a-z][a-z]*$/
but how do I get the word that was matched to appear again. That is where the \( \) brackets
work. I tell vi to remember the matched string, which it places in the variable \1. I then use it in
the replacement string:
:1,$s/ [ ]*\([a-z][a-z]*\)$/@\1/
The result is
Albert Sionov
Andrzej Such
Jacek Szulc
Khai Tran
Karl Treen
asionov@shiva
asuch@shiva
jszulc@hejira
ktran@hejira
ktreen@hejira
Finally, I want to make the last word on the line the first word, and the first two words, the last
two. I can do this by remembering the three words and re-ordering them.
:1,$s/\([a-zA-Z][a-zA-Z]*\) [ ]*\([a-zA-Z][a-zA-Z]*\) [ ]*\(.*\)$/\3 \1 \2/
11 of 13
\1
\2/
which saves the first match into \1, saves the second into \2 and the third into \3. The first and
second patterns match words that have upper and lowercase letters. The third matches any string
at the end of a line. The result is
asionov@shiva
asuch@shiva
jszulc@hejira
ktran@hejira
ktreen@hejira
Albert Sionov
Andrzej Such
Jacek Szulc
Khai Tran
Karl Treen
I could have done this transformation using a single substitute command, but it would have been
a lot of typing, and one small mistake would have required retyping the whole line, so it is not
worth the challenge. It may not look like this on your screen because the tab character settings
determine how close the second column will be to the first.
Example 2
Suppose that you want to modify a file containing ordinary text consisting of sentences and
paragraphs so that every sentence starts on a new line. Assume that all sentences end in either a
period, question mark, or exclamation mark, and that a new sentence is separated from the
previous sentence by one or more spaces, as is the convention. Then you need to replace the
sequence consisting of the end-of-sentence mark, one or more spaces, first character of new
sentence by the sequence consisting of the end-of-sentence mark, newline/carriage-return, first
character of new sentence. Note that sentences that start paragraphs will not be changed if you
do this because they already have a newline/carriage-return preceding them. The vi command to
do this is
:1,$s/\([\.\?\!]\) [ ]*\(.\)/\1^V^M\2/g
Notes
1. When you type the Control-V (^V) it will not be visible. When you then type the Control-M,
it will appear as a ^M on the command line.
2. The g on the end is the global flag, which means that if there is more than one match on a
line, it should apply the substitution to all matches, from left to right.
3. The characters ".", "?", and "!" must be escaped inside the [] operator.
4. The \1 and \2 are the strings that matched the first \(\) and the second \(\) respectively.
Example 3
Suppose that you want to change a C or C++ program so that every assignment operator has
white space on either side of it. You are not sure whether they all do some might and some
might not. The following two vi substitution will do the trick.
12 of 13
The first pattern is any character other than space or "=" followed by a "=". If there is a match,
this two character sequence is replaced by the matched character then " =". The second pattern is
the symmetric equivalent. I exclude the "=" because I do not want to modify equality
comparisons. The "g" flag is just in case there are multiple assignments on a row.
Resources
http://www.eng.hawaii.edu/Tutor/vi.html
A web site with a good tutorial on vi. But be warned they view vi as having only two states,
not three.
http://www.download.com/Software-Online/3260-20_4-54451.html
This is the page from which you can download Lemmy as well as WinXS. Lemmy is a UNIX vi
application that runs on almost all versions Windows. It lets you use almost all of the standard vi
editing commands and also supports the traditional Windows cut and paste features. It is not
exactly like vi, but close enough. It is worthwhile to download Lemmy and use it. When I write
programs for UNIX on my Windows system at home, I write them in Lemmy and then upload
them to the UNIX system via an FTP application.
13 of 13