UNIX USER TRAINING


Session 4 : vi Demystified


Objectives


This session will cover the following topics


The UNIX text editors

Vi Modes

Vi Commands

A first vi session

Delete (d), Yank (y) and Put (p)

Substitution

1) The UNIX text editors


There are many UNIX text editors. These range from basic line editors, like ed, to fully functional word processors like StarOffice Writer. In between are full-screen editors, like vi and EMACS, and graphical editors running under X-Windows, such as xedit and dtpad.


The subject of UNIX text editors has caused numerous “holy wars” on Usenet and similar hacker networks. Particularly savage have been the vi versus EMACS debates. This session skips over the religious issues and concentrates on vi. Before continuing, however, a short history is necessary.


The first UNIX text editor was ed. As the man page clearly states: “The ed utility is the standard text editor”. Ed is a terse, tricky-to-use and hence little-used line editor. Being a line editor means ed does not display a full screen of text but rather operates on a single line (or group of addressed lines) at a time. Adding more functionality to ed led to the development of ex, another line editor which this time included a display editing facility, i.e. you could now look at, and move around, a full screen of text. Vi grew out of ex, with an emphasis on the display (screen orientated) editing mode of the older editor.


Incidentally, vi should be pronounced V-I (vee eye), not as in the first syllable of violin.


For a discussion of vi, EMACS, holy wars, UNIX and computers in general, see The Jargon Lexicon at http://www.tuxedo.org/~esr/jargon/html/The-Jargon-Lexicon-framed.html .


What is vi?


This question, at least, can be answered simply.


Vi is a mode-based, plain-text, full-screen text editor.


But what does this mean in practice? Taking the description in reverse order:



The .exrc file


The .exrc file is normally found in a user’s home directory and contains the initialization commands and user-defined set up information used by vi when it starts up. Why is it called .exrc? Simply because it is actually the initialization file historically used by ex and, by extrapolation, vi. (As a general rule in UNIX, if a file starts with . (dot) and ends in rc, don’t delete it. It is probably a runtime control file for a particular program; settings might be lost if such files are deleted.)


The .exrc file can be used to define



The subjects of macros and abbreviations are beyond the scope of this session but may be covered in a future “advanced vi techniques” session. We will look at some useful vi settings.


showmode


This is probably the most massively useful option. In essence, it tells you which mode, as described above, you are in.


number


Displays line numbers


wrapmargin


Sets the number of columns from the right hand side of the screen at which text will be automatically wrapped.


autoindent


Once text has been indented (i.e. moved inwards from the left hand side) that indentation will be maintained until ESC (escape) is pressed. The cursor is returned to the leftmost column.


report


With this parameter set to a given value, vi will report the number of lines affected by a command if it is greater than the value set.


To set the autoindent, number and showmode options in your .exrc file, simply use set option-name . The wrapmargin and report options require a parameter (the number of columns from the right hand side and the threshold value for reporting changed lines) so set this value by appending =number to the .exrc entry. The following examples illustrate this



set showmode

set number

set autoindent

set wrapmargin=5

set report=5


These options will then take effect for all vi sessions.


To unset an option, simply prepend no to the option name, for example


set noautoindent


An option can be interactively set or unset during a vi session in Last Line mode. See below for a further description of this.


2) Vi Modes


Vi has three modes. (Some texts say vi has only two modes: ignore these books!) The three modes are:


Immediate or Command mode


This is the normal mode in which vi runs when first started up. In command mode, you can move the cursor around the screen, cut and paste text, delete text.


Text Input mode


In this mode vi will accept the text which is to form or modify the file’s content.


Last Line (or ex) mode


In this mode vi will accept ex-style commands. It is called Last Line mode because the cursor is moved to the bottom line of the screen. This mode is used for search-and-replace operations, opening, saving and inserting files, and setting vi optional parameters.


Moving between modes is summarised in the diagram below.


To explain:


When first entering vi (e.g. with the command vi foo) we begin in Command mode. In this mode we can move the cursor around the screen and through the file. We can copy, paste and delete blocks (lines, words or characters) of text.


On the left hand side of the diagram, entering one of the characters : / ? or ! makes vi go into Last Line mode. In this mode we can perform search and replace operations, load new files, save existing work and execute shell commands. We can also set or unset vi options such as showmode.


To terminate Last Line mode and go back to Command mode either



On the right hand side of the diagram, entering one of the characters A, a, I, i, O, o, C, c, S, s or R will place vi into Text Input mode. In this mode, you can enter the text of your document.


To terminate Text Input mode, simply press ESCAPE. This will return vi to Command mode.


The most important point to note about switching between modes is this:


You cannot move directly between Text Input mode and Last Line mode. Pressing ESCAPE in either of these modes will return vi to Command mode; then you can select the mode you want. If in doubt, press ESCAPE a couple of times. This will ensure you are in Command mode before proceeding.


3) Vi Commands


So much for moving between modes. What do all these cryptic-looking mode-changing commands actually mean? And, more importantly, how do you go about using the copy, delete, paste and substitute functions? These subjects are addressed below.


Vi commands merely look cryptic. In fact, they are (mostly) quite logically arranged. However, there are dozens of vi commands and the case-sensitivity of UNIX adds to the confusion for the newbie.


Text Input commands


Any of the following commands, entered in Command mode, will put vi into Text Input mode:



A append at end of current line

a append after current cursor position

I insert at start of current line

i insert before current cursor position

o open a new line below the current line

O open a new line above current line


The following commands also place vi into Text Input mode:


C change to end of line

c change on the current line

S substitute current line

s substitute at least one character

r replace (overstrike) on the current line


C, c, S, s and R are all quite similar in effect and are most useful when followed by other characters to modify their behaviour. Such modifiers are described in a later section.


Command mode commands


Command mode is largely concerned with cursor positioning (i.e. location within the file) and copy/cut/paste-type operations.


Gross movement by lines or screens is accomplished with the following commands


k,j,h,l up, down, left, right (cursor arrows also work on some terminals)

ctrl-F Forward one full screen

ctrl-B Back one full screen

ctrl-D Forward half a screen

ctrl-U Back half a screen

H go to top line of the screen

L go to last line of the screen

M go to middle line of the screen

G go to bottom line of the file


It is also possible to move by words or strings. For purposes of this discussion, a word is a series alphanumeric characters and/or the underscore, separated by blanks, hyphens, or other punctuation marks, while a string is a series of any printable characters, separated by blanks.


w moves forward one word

b moves back one word

e end of current word

W moves forward one string

B moves back one string

E end of current string


Described in more detail in the vi man page are methods for moving by sentence, paragraph, section or function.


While searching through a file is often initiated by a Last Line mode command (see below), the search can be continued in Command mode using the following commands


n repeat last search made with / or ?

N reverse last search made with / or ?


There are a few special command mode commands, notably


r replace character under the cursor

. (dot) repeat last change

d Delete (cut)

D Delete to end of current line

Y yank (copy)

p put (paste) after current cursor position

P put (paste) before current cursor position


Doubling the letter (dd or yy) affects the whole of the current line, while adding w or W (for instance dw, dW, yw or yW) means the command will take effect on words or strings (as defined above). If the trailing character (ydwW) is omitted, the d and y commands will operate on individual characters.


Further, d and y can be preceded by a count figure indicating how much text is to be affected. For example


dd deletes the current line

3dd deletes three lines from the current cursor position

yw yanks (copies) the current word

yW yanks (copies) the current string

3yw yanks (copies) three words


More detailed examples of these commands can be found below.


Last Line mode commands


There are four important Last Line commands


/string search for string forwards through the file

?string search for string backwards through the file

!! shell escape

:command any ex or ed command


Of these, the / and ? commands are largely self explanatory. Entering one of these characters in Command mode will place the cursor on the last line of the screen. Type the string for which you are searching, hit return and vi will find the next (or previous) occurrence of that string. Thus


/foo

?bar


The simple strings (foo, bar) are merely examples. A search can also be performed for a regular expression, that is, a string containing the pattern matching wildcards and other special features common to the grep family of commands. For example


/^foo search forward for lines beginning with foo

?bar$ search backwards for lines ending in bar

/b[aA]r search forward for occurrences of the strings bar and bAr


See the discussion of the grep command for more detailed examples of these regular expressions.


As stated earlier, the command mode n or N commands will repeat the last search, reversing direction as appropriate.


The !! shell escape function allows the results of a shell command to be read directly into the vi editing buffer. While two ! are required, the first one seems to be invisible: it is the second ! which places the cursor on the last line. Thus:


!!ls


will place the cursor on the last line, run the ls command and place the output into the file being edited in vi .


The : is the most important Last Line operator. It can be used to set vi options (like showmode), run a shell or use ex commands to delete, yank and substitute text. Be careful here, because the command


:10d


will delete line 10, while the command


:d10


will delete 10 lines from the current cursor position


This brings us neatly to the subject of line addressing.


Line addressing in vi


Given the previous example, it is clear that knowing which lines will be affected by last line commands is an important need. This is called line addressing.


A Last Line (ex) command can be preceded by zero, one or two line numbers, (if using two numbers, they are separated by commas) forming the address upon which the command will operate. There are two special characters which can take the place of line numbers, namely


. (dot) which means the current line

$ which means the last line


The following are legitimate examples of line addresses


. the current line, the default address for all commands

10 absolute line 10

10,20 lines 10 to 20 inclusive

10,$ line 10 to the end of file

.,$ from current line to end of file

1,$ all lines of the file


Further, line numbers can be preceded by + or signs to indicate relative addressing from the current line, thus:


-5,+5 the five lines before and five lines after the current line


Similar operations can be used in Command mode except for


4) A first vi session


The first task to perform in vi is to create a .exrc file containing the most useful vi command ever: set showmode .


Firstly, change to your home directory, simply by typing cd . Then use the UNIX command


14 colinbr@williams> vi .exrc


Assuming there is not a .exrc file present to start with, you will be presented with the following display:



~

~

~

~

~

~

~

".exrc" [New file]


The number of ~ symbols you see down the left hand side will vary according to your terminal. The cursor will be flashing in the extreme top left corner and the message at the bottom indicates that .exrc is a new file.


Vi has started in command mode. We need to enter text input mode in order to type our text. To do this, type i (insert before current cursor postion). You will not see any change in your screen display! But believe it or not, you are now in Text Input mode. Then type:


set showmode

~

~

~

~

~

~

~

".exrc" [New file]


This is all we require in this file. To exit text input mode, hit Escape. Notice that the cursor position moves back (left) one character: this is nothing to worry about. Now we must save our work and exit vi. Do this with the last line command :wq (colon to enter last line mode, followed by w to write the file and q to quit), thus


set showmode

~

~

~

~

~

~

~

~

:wq


Vi will report something like


".exrc" [New file] 1 line, 13 characters


and return you to the shell prompt. Now edit a new file and enter some random text. You will see something like this:


15 colinbr@williams> vi foo



This is a line of text ...


... and this is another

~

~

~

~

"foo" [New file] INSERT MODE


Notice here the effect of “set showmode”. After typing i (for insert) the phrase INSERT MODE is displayed on the last line of the screen. Hit Escape to return to command mode and the INSERT MODE indicator disappears. You can now exit the file with the usual :wq Last Line command.


5) Delete (d), Yank (y) and Put (p)


These three commands are the vi equivalents of standard word processor functions Cut, Copy and Paste. We have seen briefly how these commands are formulated. In this section, we will put these commands to work. The examples below refer to blocks of lines, but could easily apply to words or strings.


To move a block of text (i.e. cut it from one location and paste it into another), firstly position the cursor on the first line of the block, then issue the delete command in Immediate mode:


5dd


In this example we are cutting 5 lines. Now move to where you want the text inserted and put (paste) the text back, again in Command mode:


P or p


Remember that P will put the text back before the current cursor position and p will put the text back after the current cursor position.


To copy a block of text (i.e. don’t delete the original) again first move to the block of text and issue the command


5yy


Here, we are copying 5 lines. Now move to the new location and use P or p to put (paste) the text.


Lines, words or strings acted upon by yank or delete are stored in a buffer. This buffer will not be emptied until you exit vi, nor will its contents be overwritten until a subsequent yank or delete operation. In practice, this means it is possible to repeatedly put (paste) such text from the buffer into the file being edited.


6) Substitution


The s (substitute) command is used as a search and replace function in vi .


Vi’s search functions, the last line commands / and ? , have been discussed above. In this section we will learn how to replace text that has been found by a search. This is quite a complex operation and it brings together a lot of what we have seen in this session: Last Line command mode; line addressing; and searching for regular expressions. A generic search and replace command would be


:n1,n2s/find_string/replace_string/flags


The parts of this command are as follows


: used to begin a Last Line mode command

n1,n2 comma-separated line addresses

s the substitute command

find_string the string or regular expression to be found

replace_string the string to with which to replace find_string

/ characters separate (delimit) find_string from replace_string

flags are optional and may be one or both of

p print the line found

g global i.e. replace all occurrences of find_string if more than one is found on a given line


Examples of substitute commands are shown below


:1,10s/foo/bar/


On lines 1 to 10, substitute the first occurrence (only) of the string foo with the string bar


:1,10s/foo/bar/g


On lines 1 to 10, substitute all occurrences (global) of the string foo with the string bar


:1,$s/foo/bar/g


As above but on all lines of the file ($ is a special character meaning the last line of the file).


Remember that in all these examples, foo can be a grep-style regular expression.


Ampersand replacements


The & (ampersand) is a special character in the substitute command. When used in the replace_string , & represents whatever pattern was matched by the find_string . Thus, ampersand substitutions can be used to preserve whatever was found, effectively inserting replace_string before find_string , thus:


:1,$s/bar/foo&/g


This command will find all occurrences of bar and replace any hits with foobar i.e. the replace_string foo plus the find_string bar , as represented by & .


Is this of any use? In shell-scripts or configuration files, the # symbol often represents a comment. It may be necessary to comment-out several lines of code in such a file. In this case, use a command like


:20,50s/^./#&/


which means: on lines 20 to 50 replace all lines beginning with any character (the . in this case is a special regular expression meaning any character) with a # symbol followed by the rest of the line.


Substituting slashes


What if the string you want to search and replace contains slashes (/)? UNIX pathnames for example. The / is a special character to the substitute command and could cause confusion. If you want to change occurrences of the path /dc/tmp0/pcift to /sd/web/images , you cannot use the following command:


:1,$s//dc/tmp0/pcift//sd/web/images/g


Why? Because the substitute command assumes that the first two slashes delimit the find_string (an empty string) , the replace_string is taken to be dc (between the second and third / characters). The rest of the command is ignored and generates an error: “Extra characters at end of "substitute" command”.


There are two ways around this problem.


Firstly, it is possible to switch off (or escape) the special meaning of the / character by preceding it with a backslash (\). Using this method, the previous command becomes:


:1,$s/\/dc\/tmp0\/pcift/\/sd\/web\/images/g


The substitute command interprets any non-escaped characters as the delimiters for the find_string and replace_string . Any / character immediately preceded by a \ is taken as literal text.


It is obvious that this can get messy. An easier solution to this problem is to use a different character as the delimiter for find_string and replace_string . Simply put, any character that doesn’t appear in either find_string or replace_string can be used as the delimiter. In practice, it is best to choose the delimiter from a range of punctuation marks or mathematical symbols, for example +, =, !, >, < or # . The command above can be replaced with any of the following:


:1,$s+/dc/tmp0/pcift+/sd/web/images+

:1,$s!/dc/tmp0/pcift!/sd/web/images!

:1,$s=/dc/tmp0/pcift=/sd/web/images=

:1,$s#/dc/tmp0/pcift#/sd/web/images#