Remember when we first starting talking about searching, I mentioned that the expression you were looking for was held in
a buffer. Also, whatever was matched by /[Bb][Oo][Aa][Tt] can be held in a buffer.
We can then use that buffer as part of the replacement expression. For example, if we wanted to replace
every occurrence of "UNIX" with "Linux," we could do it like this:
The scope of this command is defined by the %, the shortcut way of referring to the entire text.
Or, you could first save "UNIX" into a buffer, then use it in the replacement
expression. To enclose something in a buffer, we enclose it within a matching pair of back slashes
\( and \)
to define the extent of a buffer. You can even have multiple pairs that define the extent of multiple buffers.
These are reference by \#, where # is the number of the buffer.
In this example
the text "UNIX," is placed into the first buffer.
You then reference this buffer with \1 to say to vi to plug in the contents of the first buffer.
Because the entire search pattern is the same as the pattern buffer, you could also have written it like this
in which the ampersand represents the entire search pattern.
This obviously doesn't save much typing. In fact, in this example, it requires more typing to save "UNIX" into the buffer
and then use it. However, if what you wanted to save was longer, you would save time. You also save time
if you want to use the buffer twice. For example, assume you have a file with a list of other files, some of them
C language source files. All of them end in .c. You now want to change just the names of the C files so that
the ending is "old" instead of .c. To do this, insert mv at the beginning of each line as well as produce two
copies of the file name: one with .c and one with .old. You could do it like this:
:%s/^\(.*\)\.c/mv \1.c \1.old/g
In English, this line says:
- For every line (%)
- substitute (s)
- for the pattern starting at the beginning of the line (^), consisting of any number of characters ( \(.*\) ) (placing this pattern into buffer
#1) followed by .c
- and use the pattern mv, followed by the contents of buffer
#1 (\1), followed by a .c, which is again followed by the contents of buffer #1, (\1) followed by .old
- and do this for every line (g), (i.e., globally)
Now each line is of the form
mv file.c file.old
Note the slash preceeding the dot in the expression "\.c". The slash "protects" the dot from
being interpreted as the metacharacter for "any character". Instead, you want to search
for a literal dot, so you need to protect it.
We can now change the permissions
to make this a shell script and execute it. We would then move all the files as described above.
Using numbers like this is useful if there is more that one search pattern that you want to process.
For example, assume that we have a three-column table for which we want to change the order of the
columns. For simplicity's sake, lets also assume that each column is separated by a space so as not to
make the search pattern too complicated.
Before we start, we need to introduce a new concept to vi, but one that you have seen before: [ ]. Like the
shell, the square bracket pair ([ ]) of vi is used to limit sets of characters.
Inside of the brackets, the caret (^) takes on a new meaning. Rather than
indicating the beginning of a line, here it negates the character we are searching for. So we could type
%s/\([^ ]*\) \([^ ]*\)
/\3 \1 \2/g
Here we have three regular expressions, all referring to the same thing: \([^ ]*\). As we discussed above,
the slash pair \( and \) delimits each of the buffers, so everything inside is the search pattern. Here, we are
searching for [^ ]*, which is any number of matches to the set enclosed within the brackets. Because the
brackets limit a set, the set is ^, followed by a space. Because the ^ indicates negation, we are placing any
number of characters that is not a space into the buffer. In the replacement
pattern, we are telling vi to print pattern3, a space, pattern1, another space, then pattern2.
In the first two instances, we followed the pattern with a space. As a result, those spaces were not saved into
any of the buffers. We did this because we may have wanted to define our column separator differently.
Here we just used another space.
I have often had occasion to want to use the pattern buffers more than once. Because they are not
cleared after each use, you can use them as many times as you want. Using the example above, if we change
\([^ ]*\) \([^ ]*\)/\3 \1 \2 \1/g
we would get pattern3, then pattern1, then pattern2, and at the end, pattern1 again.
Believe it or not, there are still more buffers. In fact, there are dozens that we haven't touched on. The
first set is the numbered buffers, which are numbered 1-9. These are used when we delete
text and they behave like a stack. That is, the first time we delete something, say a
word, it is placed in buffer number 1. We next delete a line that is placed in
buffer 1 and the word that was in buffer 1 is placed in buffer 2. Once all the numbered buffers all full,
any new deletions push the oldest ones out the bottom of the stack and are no longer available.
To access these buffers, we first tell vi that we want to use one of the buffers by pressing the double-quote (").
Next, we specify then the number of the buffer,
say 6, then we type either p or P to put it, as in "6p. When you delete text
and then do a put without specifying any buffer, it automatically comes from buffer 1.
There are some other buffers, in fact, 26 of them, that you can use by name. These are the named
buffers. If you can't figure out what their names are, think about how many of them there are (26). With these
buffers, we can intentionally and specifically place something into a particular buffer. First, we say
which buffer we want by preceding its name with a double-quote ("); for example,
"f. This says that we want to place some text in the named buffer f. Then, we place the
data in the buffer, for example, by deleting an entire line with dd or by deleting two words with d2w. We can
later put the contents of that buffer with "fp. Until we place something new in that buffer, it will contain what
we originally deleted.
If you want to put something into a buffer
without having to delete it, you can. You do this by "yanking it." To yank an entire line, you could done one
of several things. First, there is yy. Next, Y. Then, you could use y, followed by a movement commands,
as in y-4, which would yank the next four lines (including the current one), or y/expression, which would
yank everything from your current position up to and including expression.
To place yanked data into a named buffer
(rather than the default buffer, buffer number 1), it is the same procedure as when you delete. For example, to
yank the next 12 lines into named buffer h, we would do "h12yy. Now those 12 lines are available to us.
Keep in mind that we do not have to store full lines. Inputting "h12yw will put the next 12 words into
Some of the more observant readers might have noticed that because there are 26 letters and each has both an upper- and lowercase, we could have 52 named buffers. Well, up to now, the uppercase letters did something different. If uppercase letters were used to designate different buffers, then the pattern would be compromised. Have no fear, it is.
Instead of being different buffers than their lowercase brethren, the uppercase letters are the same buffer.
The difference is that yanking or deleting something into an uppercase buffer appends the contents rather
that overwriting them.
You can also have vi keep track of up to 26 different places with the file you are editing. These functions are just like bookmarks in word processors. (Pop quiz: If there 26 of them, what are their names?)
To mark a spot, move to that place in the file, type m for mark (what else?), then a single back
quote (`), followed by the letter you want to use for this bookmark. To go back to that spot, press the
back quote (`), followed by the appropriate letter. So, to assign a bookmark q to a particular spot, you
would enter `q. Keep in mind that reloading the current file or editing a new one makes you lose the
Note that with newer version of vi (particularly vim) you don't press the backquote to set
the mark, just m followed by the appropriate letter.