Cookbook

This is the vi cookbook page. It contains short recipes for doing many simple and not so simple things in vi. You should already know the basics of vi, however each command is explained in detail.

Each set of instructions is a complete package. Feel free to pick and choose what you need.

Contents

Character twiddling
Interactively replacing one word with another
Replacing one word with another using one command
Moving Text
Copying a block of text from one file to another
Sorting a section
Dealing with Makefile and other SOB files
Formatting a text paragraph
Finding a procedure in a C program
Drawing comment boxes
Reading a man page
Removing carriage returns from MS-DOS file
Trimming the blanks off an end of line
Oops, I left the file write protected
Changing "Last, First" to "First Last"
How to edit all the files containing a given word

Character twiddling

If you type fast your fingers can easily get ahead of your mind. Frequently people transpose characters. For example the word "the" comes out "teh".

To swap two characters, for example "e" with "h", put the cursor on the cursor on the "e" and type xp.

The "x" command deletes a character (the "e") and the "p" pastes it after the cursor (which is now placed over the "h".)

Interactively replacing one word with another

Suppose you want to replace every occurrence of the word "idiot" with the word "manager". But you want the chance to review each change before you do it.

Here's what you do:

1. 1G Go to the top of the document
2. /idiot<enter> Find the first occurrence of the word "idiot"
3. cwmanager Change the word (cw) to manager.
4. n Repeat the last search (find the next idiot.)
5. . Repeat the last edit (change one word to manager)
(If you do not want to change the word, skip this step.)

Repeat steps 4 and 5 until you have replaced all occurred.


Replacing one word with another using one command

Suppose you want to make all "idiots" into "managers" and you don't need to review your changes.

Execute the command:

The colon (:) indicates that we are going to execute an ex type command. All ex command begin with range of line numbers on which the command operates. In this case, we've chosen the whole document from line 1 to the last line ($).

The "s" command performs a substitution. The old text follows enclosed in slashes (/idiots/). The replacement text comes next also delimited by the slash (/managers/). The "g" command tells the editor that this is a global change and so if the word "idiots" appears more than once on a line, to change them all.

Moving Text

Suppose you want to move a paragraphs from the top of the document to the bottom.

Execute the commands:

1. Move the cursor to the top of the paragraph you want to move.
2. ma Place a mark named "a" at this location.
3. Move the cursor to the bottom of the paragraph to be moved.
4. d'a Delete to mark "a". This puts the deleted text in a cut buffer.
5. Move the cursor to line where the text is to go. The paragraph will be placed after this one.
6. p Paste the text in below the cursor.

Copying a block of text from one file to another

The vi command does not handle multiple files very well. However you can get text from one file to another without too much trouble.

To copy a block of text between files execute the commands:
1. Edit the first file.
2. Go to the top line to be copied.
3. ma Mark this line as mark "a".
4. Go to the bottom line to be copied
5. :'a,.w! tmp.txt The colon : indicates a ex style command. The 'a,. is a line number range. In this case the range starts on the line marked a ('a) and ends on the current line (.). The w is the command to write the lines to a file. In case the file already exists an overwrite is forced with !. Finally we reach tmp.txt the name of the file.
6. :q Get out of the original file.
7. Edit the file which will receive the text.
8. Go to the line where the insert is to occur. The text will be place after this line.
9. :r tmp.txt Again you are executing a ex style command. This time it's read (r) and the file is tmp.txt.

This procedure leaves a small file "tmp.txt" in the current directory. You can delete this if you want. In practice I just leave them there. I just looked on my home system and found 15 of them lying about.

Sorting a section

Frequently you will be editing a file with a list of names in it. For example, a list of object files that make up a program.

For example:

	version.o  	
	pch.o		
	getopt.o 	
	util.o		
	getopt1.o	
	inp.o		
	patch.o		
	backupfile.o

This list would be nice in alphabetical order. Or at least ASCII order. To alphabetize this list execute the commands:

1. Move the cursor to the first line to be sorted.
2. ma Mark the first line as mark a.
3. Move to the bottom of the text to be sorted.
4. !'asort The ! command tells vi to run the text through UNIX command. The 'a tell the editor that the text to be worked on starts at the current line and ends at mark a. The command that the text is to go through is sort.

The result looks like:

	backupfile.o
	getopt.o 	
	getopt1.o	
	inp.o	
	patch.o		
	pch.o		
	util.o		
	version.o  	

Warning

In actual practice what you in most Makefiles (file that are used by UNIX to control compilation) looks more like:

OBJS = \
        version.o       \
        pch.o           \
        getopt.o        \
        util.o          \
        getopt1.o       \
        inp.o           \
        patch.o         \
        backupfile.o

Notice that the backslash (\) is used to indicate a continuation line. After sorting this looks like:

OBJS = \
        backupfile.o
        getopt.o        \
        getopt1.o       \
        inp.o           \
        patch.o         \
        pch.o           \
        util.o          \
        version.o       \

The names are in order, but the backslashes are wrong. Don't forget to fix them using normal editing before continuing.

OBJS = \
        backupfile.o    \
        getopt.o        \
        getopt1.o       \
        inp.o           \
        patch.o         \
        pch.o           \
        util.o          \
        version.o

Dealing with Makefile and other SOB files

One problem with the file format used by the UNIX make command is that it's extremely fussy.

For example, the following is correct:

        prog: prog.c
                cc -g -o prog prog.c

The following is not:

        prog: prog.c
                cc -g -o prog prog.c

At first glance you might think that these two are exactly. But look closer. The "cc" line of the first one begins with a tab. The second one begins with eight spaces. (You can't tell the difference between a space and a tab when it's printed on the screen! You need a better video card.)

So how are you supposed to tell them apart especially when one the screen (or the printed page) they look exactly the same.

The answer is you can't. You might think that's a bit unfair. Especially when make works on the first one but not the second. But who every said UNIX was fair.

Fortunately vi has a mode that tells you exactly what's in your file. Executing the command

	:set list
puts you into this mode. When the display is set into "list mode" all characters print. Tabs show up as "^I" and the end of line shows up as $. So in list mode, our two examples look like:
        prog: prog.c$
        ^Icc -g -o prog prog.c$

and

        prog: prog.c$
                cc -g -o prog prog.c$

From this it's easy to see which line has the tab.

Formatting a text paragraph

The vi editor is not a word processor. Boy is it not a word processor. There are a couple of things you can do to make things better for you when editing text.

Word processors automatically wrap when you type a line that's longer than the margins. The vi editor lets make a line as long as you want. By executing the command:

        :set wrapmargin=70

you can tell vi to automatically break lines when the run longer than 70 characters. (You can adjust this number to whatever line length you want.)

This makes entering text much easier. It doesn't solve the problem of editing. If you enter a paragraph and then decide to delete half the words on the first line, vi will not reformat the text.

You can force a reformat of a paragraph by executing the commands:
1. Move to the top of the paragraph.
2. !} The "!" command tells vi to pipe a section of text through a filter. The } tells vi that the section of text for the pipe command is a single paragraph.
3. fmt -70 The UNIX command fmt is a primitive formatter. It performs word-wrapping well enough for text documentation. The -70 tells fmt to format lines for 70 characters per line.

Finding a procedure in a C program

The vi program was designed by programmers for programmers. You can use it to locate procedures within a set of C or C++ program files.

But first you must generate a table of contest file called a "tags" file. (This file has been given the obvious name tags.) The ctags command generates this table of contents files.

To generate a table of contents of all the C program files in your current working directory, use the command:

        $ ctags *.c

For C++ use the command:

        $ ctags *.cpp

If you use an extension other than .cpp for your C++ files, use it instead of .cpp.

Once this file is generated, you tell vi that you want edit a procedure, and it will find the file containing that procedure and position you there. For example if you want to edit the procedure write_file use the command:

        $ vi -t write_file

Now suppose as you are looking at the write_file procedure that it calls setup_data and you need to look at that procedure. To jump to that function, position the cursor at the beginning of the word setup_data and press Ctrl+]. This tells vi to jump to the definition of this procedure. This repositioning will occur even if vi has to change files to do so.

Note:

If you've edited the current file and not saved it, vi will issue a warning and ignore the Ctrl+] command.

Drawing comment boxes

I like to put a big comment box at the top of each of my procedures. For example:

	/*******************************************************
	 * Program -- Solve it -- Solves the worlds problems.  *
	 *     All of them.  At once.  This will be a great    *
	 *   program when I finish it.                         *
	 *******************************************************/

Drawing these boxes like this is tedious at best. But vi has a nice feature called abbreviations that makes things easier.

First, you need to create a vi initialization file called ~/.exrc. (At first this may look like a ex initialization file. It is. The vi command is actually a mode of the ex editor.)

The ~/.exrc file need to contain the lines:

        :ab #b /************************************************
        :ab #e ************************************************/

These command define a set of vi abbreviations. What's a vi abbreviation? Its a word that stands for another word. When vi see the abbreviation, it will expand it to the full word. In this case we've defined an abbreviation called #b that expands to the beginning line of a comment box. The #e abbreviation does the same thing.

So to create a comment box enter #b<enter>. The screen looks like:

        /************************************************
Enter the comments, including the beginning and ending "*" characters. Finally end the comment by typing #e<enter>. This causes the ending comment to be entered.

Note:

This page was written in vi. So how did we enter the #b and #e? Easy, we typed in #bb and the deleted a character. (We couldn't enter #b or it would have been expanded.)

Some other useful commands that programmer may want to put in their ~/.exrc include:

	:set autoindent
	:set autowrite
	:ab #d #define
	:ab #i #include
	:ab #b /************************************************
	:ab #e ************************************************/
	:ab #l /*----------------------------------------------*/
	:set sw=4

The autoindent setting causes vi to indent new lines by a similar amount to the one next to them. This is very useful for entering programs. The autowrite setting tells vi to write the old file out when switching from one file to another.

The abbreviations #d, #i, and #l, define useful terms for programmers.

Finally, the command set sw=4 sets the shift width (the number of characters text is moved sideways for the shift command (<< and >>)).

This is very useful if you use a 4 space indentation for your C or C++ programs. (Studies at Rice University have shown this to be the best indentation size.)

Reading a man page

You can use the vi editor to browse through text files. One of the most useful set of files to browse through is the man pages. Getting the man pages into vi involves the UNIX equivalent of a four corner billiards shot.

We start with the man command, throw the text into the more rail, richoette into the vi command which bounces the text through the ul command.

Whew! Actually, the step by instructions make this operation much simpler than it sounds.

Start by with man

    $ man subject
	 ....  first page of text is displayed
	 --MORE--

Type in:

	v	

This tells more to run the vi editor one the current file.

Once vi starts execute

1G Goes to the first line
!Gui -i<enter> Pipe (!) the entire text (G) through a command (ul i). The ul -i command

The ul -i command takes the backspaces out of a file and turns them into something readable.

In other words before the ul command, you'll see something like this:

	N^HNA^HAM^HME^HE
	   date - print or set the system date and time

while afterward you see something more readable.

    NAME
    !!!!
	   date - print or set the system date and time
Now you can use the normal vi command to page up, page down, and search for things.

Note:

Some versions of UNIX, such as Linux, format the man pages in a way which prevents you from using the "v" command at the "--MORE--" prompt. To get around this problem, you need to use an alternate set of commands.

Start with:

    $ man subject  >tmp.txt
    $ vi tmp.txt
Then enter the 1G!Gul -i command.

Removing carriage returns from MS-DOS file

If you ever try to edit a MS-DOS file, you'll notice that each line ends with a ^M character. This is caused by the funny way that MS-DOS treats the end-of-line. (For some background on this problem take a look at The EOL Story.

To remove the ^M characters from a MS-DOS file, enter the command:

	:1,$s/{Ctrl+V}{Ctrl+M}//{Enter}
This command starts with a colon (:) to tell vi to enter ex mode. All ex start with a line number range, in this case its from the first line (1) to the last ($). The slash indicates the start of the "from text". The {Ctrl+V} tells vi to treat the next character as a regular character even if it's a special one. The next character is {Ctrl+M}. (This would be treated as {Enter} without the {Ctrl+V}.) The next slash ends the "from text". What follows is the "to text" enclosed by slashes. In this case it's nothing (//).

Trimming the blanks off an end of line

Some people find spaces and tabs at the end of a line useless, wasteful, and ugly. To remove whitespace at the end of every line, execute the command:

	:1,$s/[ {tab}]*$//

The colon (:) tells vi to enter ex command mode. All ex commands start with a line range, in this case, the entire file (line 1 to the last line: $).

The first set of slashes enclose the "from text". The square brackets indicate that either character can be a match. So [ {tab}] matches either space or tab. The star (*) means that the previous character specification (space or tab) can be repeated any of number times. The dollar ($ indicates an end of line.

So [ {tab}]*$ tells vi to look for any number of spaces or tabs followed by an end of line.

These are then replaced by the text in the next set of slashes. This text is nothing, so the spaces and tabs are effectively removed.

Oops, I left the file write protected

Say your editing a file and you've made a lot of changes. This is a very important file and to preserve it from any casual changes, you've write protected it, even against yourself.

The vi editor allows you to edit a write protected file with little or no warning. The only trouble is that when you try to exit using "ZZ" you get the error:

    file.txt	File is read only

and vi doesn't exit.

So what can you do? You don't want to throw away all those changes, but you need to get out of vi so you can turn on write permission.

The trick is to execute the :shell command. This command takes you out of vi by starting a command processor (shell) running under vi

You can then write enable the file:

 
	$ chmod u+w file.txt
and get out of the shell, returning to vi
	$ exit

Finally you need to force vi to write the file using the command:

	:w!
(It still thinks the file is write protected so we need to use the force option (!) to convince it to try writing.)

Note:

It is a good idea to only spend as short a time as possible in a command processor started by the :shell command. That's because it's easy to forget that you're running under vi. It's possible to start a shell, that starts vi, that starts a shell, that starts vi, that .... Using this method you can easily consume a lot of resources and generate a lot of confusion.

By keeping your :shell sessions short you can avoid lots of trouble.

Changing "Last, First" to "First Last"

You have a list of names in the form:

	Last, First

How to you change them to:

	First Last
It can be done with one command:
    :1,$s/\([^,]*\), \(.*$\)/\2 \1/
The colon (:) tells vi that this is an ex style command.

The line range for this command is the whole file as indicated by the range 1,$.

The s (substitute) tells vi to do a string substitution.

The old text is a complex regular expression. The \( ... \) delimiters are used to inform the editor that the text that matches the regular expression side is to be treated special.

The text in the first \( ... \) is assigned to \1 in the replacement text. The second set of text inside \( ... \) is assigned \2 and so on.

In this case the first regular expression is any bunch of characters that does not include a comma. The [^,] means anything but a comma, the * means a bunch (zero or more characters).

The second expression matches anything: .* up to the end of line: $.

The result of this substitution is that the first word on the line is assigned to \1 and the second to \2. These values are used in the end of the command to reverse the word.

The figure below shows the relationship between the \( \) enclosed strings and the \1, \2 markers.

	:1,$s/\([^,]*\), \(.*$\)/\2 \1/
	      ^^     ^^  ^^   ^^^ ^  ^            
	      ||     ||  ||   ||| |  +-----  String matched by 
	      ||     ||  ||   ||| |          first \( \)
	      ||     ||  ||   ||| +--------- String matched by
	      ||     ||  ||   |||            second \( \)
	      ||     ||  ||   ||+----------- Slash separating 
	      ||     ||  ||   ||             old/new strings
	      ||     ||  ++---++------------ Second \( \) 
	      ++-----++--------------------- First \( \)

The next figure breaks out the various parts of the regular expressions used in this example.

	:1,$s/\([^,]*\), \(.*$\)/\2 \1/
		^^^^^  ^^  ^^^
		|||||  ||  ||+--- The end of the line
		|||||  ||  |+---- Repeated 0 or more time
		|||||  ||  +----- Any character
		|||||  ||  +++--- Any character, repeated,
		|||||  ||             followed by EOL
		|||||  |+-------- The character space
		|||||  +--------- The character comma
		||||+------------ Repeated 0 or more times
		|||+------------- Closes the [] expression
		||+-------------- The character comma
		|+--------------- Match anything except the
		|                 next character
		+---------------- Starts a set of matches
		++++------------- Match anything but comma
		    +------------ Repeated 0 or more times
		       +--------- Followed by comma

How to edit all the files containing a given word

This involves the fgrep as well as the special shell character backtick (`).

To edit all the C program files that contain the word indentation_level execute the command:

    $ vi `fgrep -l indentation_level *.c`

The fgrep -l indentation_level *.c searches all the files ending with .c for the word and lists them out.

Since this command is enclosed in backtick (`) characters the results of the command (a list of files) takes the place of the command on the command line.

The vi editor is then run on these files. The commands :n{Enter} and :rew{Enter} can then be used to browse through the files.