Полезная информация

Previous Page TOC Next Page Home


7 — Text Editing with vi, EMACS, and sed

By Dave Taylor

The vi Editor

If you like primitive tools, you've already figured out that you can use a combination of << and cat to add lines to a file, and you can use sed and file redirection to modify the contents of a file. These tools are rough and awkward, and when it's time to either create new files or modify existing ones, you need a screen-oriented editor. In UNIX, the screen editor of choice is called vi.

There are a number of editors that may be included with your UNIX system, including ed, ex, vi, and EMACS. The latter two use the entire screen, a big advantage, and both are powerful editors. This section focuses on vi, however, because it's easier and, perhaps more importantly, it's guaranteed to always be part of UNIX. Most vendors omit EMACS, forcing you to find it yourself.

In this section, you will learn how to start and quit vi, simple character motion in vi, how to move by words and pages, how to insert text into the file, how to search within a file, how to have vi start out right, the key colon commands in vi.

In some ways, an editor is like another operating system living within UNIX. If you're used to Windows or Macintosh editors, you'll be unhappy to find that vi doesn't know anything about your mouse. Once you spend some time working with vi, however, it will grow on you. By the end of this section, you will be able to create and modify files on your UNIX system to your heart's content.

How to Start and Quit vi

Most UNIX commands do their work, display their results, and quit. Among the few exceptions are more and pg, where you work within the specific program environment until you have viewed the entire contents of the file being shown, or until you quit. The vi editor is another program in this small category of environments, programs that you move in and use until you explicitly tell the program to quit.

Before you start vi for the first time, you must learn about two aspects of its behavior. The first is that vi is a modal editor. A mode is like an environment. Different modes in vi interpret the same key differently. For example, if you're in insert mode, pressing the A key adds an a to the text, whereas in command mode, pressing the A key enters a, a single key abbreviation for the append command. If you ever get confused about what mode you're in, press the Esc key on your keyboard. Pressing Esc always returns you to the command mode (and if you're already in command mode, it beeps to remind you of that fact).


TIP: In vi, the Enter key is a specific command (meaning move to the beginning of the next line). As a result, you never need to press Enter to have vi process your command.


NOTE: EMACS is a modeless editor. In EMACS, the A key always adds the letter a to the file. Commands in EMACS are all indicated by holding down the Ctrl key while pressing the command key; for example, Ctrl+C deletes a character.

The second important characteristic of vi is that it's a screen-oriented program. It must know what kind of terminal, computer, or system you're using to work with UNIX. This probably won't be a problem for you, because most systems are set up so that the default terminal type matches the terminal or communications program you're using. Here you will learn how to recognize when vi cannot figure out what terminal you're using, and what to do about it.

You can start vi in a number of different ways, and you will learn about lots of helpful alternatives later. Right now you will learn the basics. The vi command by itself starts the editor, ready for you to create a new file. The vi command with a filename starts vi with the specified file, so you can modify that file immediately.

To begin, enter vi at the prompt. If all is working well, the screen will clear, the first character on each line will become a tilde (~), and the cursor will be sitting at the top-left corner of the screen:

% vi

_

~

~

~

~

~

~

~

~

~

~

Type a colon character. Doing so moves the cursor to the bottom of the screen and replaces the last tilde with a colon:

~

~

~

~

~

~

~

~

:_

Press the q key and the Enter key, and you should be back at the shell prompt:

~

~

~

~

~

~

~

~

:q

%

If that operation worked without a problem, go ahead and append your command to your .login or .profile file. If the operation did not work, you received the unknown-terminal-type error message. You might see this on your screen:

% vi

"unknown": Unknown terminal type

I don't know what type of terminal you are on. All I have is "unknown"

 [using open mode]

_

Alternatively, you might see this:

% vi

Visual needs addressible cursor or upline capability

:

Don't panic. You can fix this problem. The first step is to get back to the shell prompt. To do this, do exactly what you did in the first step: type :q and press Enter. You should then see this:

% vi

"unknown": Unknown terminal type

I don't know what type of terminal you are on. All I have is "unknown"

 [using open mode]

:q

%

The problem here is that vi needs to know the type of terminal you're using, but it can't figure that out on its own. Therefore, you need to tell this to the operating system by setting the TERM environment variable. If you know what kind of terminal you have, use that value; otherwise, try the default of vt100:

% setenv TERM vt100

If you have the $ prompt, which means you're using the Bourne shell (sh) or Korn shell (ksh) rather than the C shell (csh), try this:

$ TERM=vt100 ; export TERM

Either way, you can now try entering vi again, and it should work. If it does work, append the command (whichever of these two commands was successful for you) to your .login file if you use csh, or to .profile if you use sh or ksh:

% echo "setenv TERM vt100" >> .login

or

$ echo "TERM=vt100 ; export TERM" >> .profile

This way, the next time you log in, the system will remember what kind of terminal you're using.

If this didn't work, it's time to talk with your system administrator about the problem or to call your UNIX vendor to find out what the specific value should be. If you are connected through a modem or other line, and you are actually using a terminal emulator or communications package, then you might also try using ansi as a TERM setting. If that fails, call the company that makes your software and ask them what terminal type the communications program is emulating.

Great! You have successfully launched vi, seen what it looks like, and even entered the most important command: the quit command. Now create a simple file and start vi so it shows you the contents of the file:

% ls -l > demo

% vi demo

total 29

drwx——— 2 taylor        512 Nov 21 10:39 Archives/

drwx———  3 taylor        512 Dec  3 02:03 InfoWorld/

drwx———  2 taylor       1024 Dec  3 01:43 Mail/

drwx———  2 taylor        512 Oct  6 09:36 News/

drwx———  4 taylor        512 Dec  2 22:08 OWL/

-rw-rw——  1 taylor        126 Dec  3 16:34 awkscript

-rw-rw——  1 taylor        165 Dec  3 16:42 bigfiles

drwx———  2 taylor        512 Oct 13 10:45 bin/

-rw-rw——  1 taylor          0 Dec  3 22:26 demo

-rw-rw——  1 taylor      12556 Nov 16 09:49 keylime.pie

-rw-rw——  1 taylor       8729 Dec  2 21:19 owl.c

-rw-rw——  1 taylor        199 Dec  3 16:11 sample

-rw-rw——  1 taylor        207 Dec  3 16:11 sample2

drwx———  2 taylor        512 Oct 13 10:45 src/

drwxrwx—  2 taylor        512 Nov  8 22:20 temp/

-rw-rw——  1 taylor        582 Nov 27 18:29 tetme

~

~

~

~

~

~

~

"demo" 17 lines, 846 characters

You can see that vi reads the file specified on the command line. In this example, my file is 17 lines long, but my screen can hold 25 lines. To show that some lines lack any text, vi uses the tilde on a line by itself. Finally, note that, at the bottom, the program shows the name of the file, the number of lines it found in the file, and the total number of characters.

Type :q again to quit vi and return to the command line for now. When you type the colon, the cursor will flash down to the bottom line and wait for the q, as it did before.

You have learned the most basic command in vi—the :q command—and survived the experience. It's all downhill from here.

Simple Character Motion in vi

Getting to a file isn't much good if you can't actually move around in it. Now you will learn how to use the cursor control keys in vi. To move left one character, press the h key. To move up, press the k key. To move down, press the j key. To move right a single character, use the l key. You can move left one character by pressing the Backspace key, and you can move to the beginning of the next line with the Enter key.

Launch vi again, specifying the demo file:

% vi demo

total 29

drwx———  2 taylor        512 Nov 21 10:39 Archives/

drwx———  3 taylor        512 Dec  3 02:03 InfoWorld/

drwx———  2 taylor       1024 Dec  3 01:43 Mail/

drwx———  2 taylor        512 Oct  6 09:36 News/

drwx———  4 taylor        512 Dec  2 22:08 OWL/

-rw-rw——  1 taylor        126 Dec  3 16:34 awkscript

-rw-rw——  1 taylor        165 Dec  3 16:42 bigfiles

drwx———  2 taylor        512 Oct 13 10:45 bin/

-rw-rw——  1 taylor          0 Dec  3 22:26 demo

-rw-rw——  1 taylor      12556 Nov 16 09:49 keylime.pie

-rw-rw——  1 taylor       8729 Dec  2 21:19 owl.c

-rw-rw——  1 taylor        199 Dec  3 16:11 sample

-rw-rw——  1 taylor        207 Dec  3 16:11 sample2

drwx———  2 taylor        512 Oct 13 10:45 src/

drwxrwx—  2 taylor        512 Nov  8 22:20 temp/

-rw-rw——  1 taylor        582 Nov 27 18:29 tetme

~

~

~

~

~

~

~

"demo" 17 lines, 846 characters

You should see the cursor sitting on top the t in total on the first line, or perhaps flashing underneath the t character. Perhaps you have a flashing box cursor or one that shows up in a different color. In any case, that's your starting spot in the file.

Press the h key once to try to move left. The cursor stays in the same spot and vi beeps to remind you that you can't move left any farther on the line. Try the k key to try to move up; the same thing will happen.

Now try pressing the j key to move down a character:

        total 29

drwx———  2 taylor        512 Nov 21 10:39 Archives/

drwx———  3 taylor        512 Dec  3 02:03 InfoWorld/

drwx———  2 taylor       1024 Dec  3 01:43 Mail/

Now the cursor is on the d directory indicator on the second line of the file.

Press the k key to move back up to the original starting spot.

Using the four cursor control keys (h, j, k, and l), move around in the file for a little bit until you are comfortable with what's happening on the screen. Now try using the Backspace and Enter keys to see how they help you move around.

Move to the middle of a line:

total 29

drwx———  2 taylor        512 Nov 21 10:39 Archives/

drwx———  3 taylor        512 Dec  3 02:03 InfoWorld/

drwx———  2 taylor       1024 Dec  3 01:43 Mail/

Here you're middle digit in the file size of the second file in the listing. Here are two new cursor motion keys: the 0 (zero) key moves the cursor to the beginning of the line, and $ moves it to the end of the line. First, press 0:

total 29

drwx———  2 taylor        512 Nov 21 10:39 Archives/

drwx———  3 taylor        512 Dec  3 02:03 InfoWorld/

drwx———  2 taylor       1024 Dec  3 01:43 Mail/

Now press $ to move to the end of the line:

total 29

drwx———  2 taylor        512 Nov 21 10:39 Archives/

drwx———  3 taylor        512 Dec  3 02:03 InfoWorld/

drwx———  2 taylor       1024 Dec  3 01:43 Mail/

If you have arrow keys on your keyboard, try using them to see if they work the same way the h, j, k, and l keys work. If the arrow keys don't move you around, they might have shifted you into insert mode. If you type characters and they're added to the file, you need to press the Esc key to return to command mode. Wrap this up by leaving this edit session. Because vi now knows that you have modified the file, it will try to ensure that you don't quit without saving the changes:

~

~

:q

No write since last change (:quit! overrides)

Use :q! (shorthand for :quit) to quit without saving the changes.


NOTE: In general, if you try to use a colon command in vi and the program complains that it might do something bad, try the command again, followed by an exclamation point. This is like saying, "Do it anyway!"

Stay in this file for the next section if you'd like, or use :q to quit.

Moving about a file using these six simple key commands is, on a small scale, much like the entire process of using the vi editor when working with files. Stick with these simple commands until you're comfortable moving around, and you will be well on your way to becoming proficient with vi.

Moving by Words and Pages

The description of the EMACS editor mentioned that because it's always in insert mode, all commands must include the Ctrl key. Well, it turns out that vi has its share of Ctrl+key commands, commands that require you to hold down the Ctrl key and press another key. In this section, you will learn about Ctrl+F, Ctrl+B, Ctrl+U, and Ctrl+D. These move you forward or backward a screen, and up or down half a screen of text, respectively.

Here are a few more commands: Ctrl+w moves you forward word by word, Ctrl+b moves you backward word by word, and the uppercase versions of these two commands have very similar, but not identical, functions.

To see how this works, you need to create a file that is larger than your screen. An easy way to do this is to save the output of a common command to a file over and over until the file is long enough. The system I use has lots of users, so I needed to use the who command just once. You might have to append the output of who to the big.output file a couple of times before the file is longer than 24 lines. (You can check by using wc, of course.)

% who > big.output; wc -l big.output

40

% vi big.output

        leungtc  ttyrV   Dec  1 18:27   (magenta)

tuyinhwa ttyrX   Dec  3 22:38   (expert)

hollenst ttyrZ   Dec  3 22:14   (dov)

brandt   ttyrb   Nov 28 23:03   (age)

holmes   ttyrj   Dec  3 21:59   (age)

yuxi     ttyrn   Dec  1 14:19   (pc115)

frodo    ttyro   Dec  3 22:01   (mentor)

labeck   ttyrt   Dec  3 22:02   (dov)

chenlx2  ttyru   Dec  3 21:53   (mentor)

leungtc  ttys0   Nov 28 15:11   (gold)

chinese  ttys2   Dec  3 22:53   (excalibur)

cdemmert ttys5   Dec  3 23:00   (mentor)

yuenca   ttys6   Dec  3 23:00   (mentor)

janitor  ttys7   Dec  3 18:18   (age)

mathisbp ttys8   Dec  3 23:17   (dov)

janitor  ttys9   Dec  3 18:18   (age)

cs541    ttysC   Dec  2 15:16   (solaria)

yansong  ttysL   Dec  1 14:44   (math)

mdps     ttysO   Nov 30 19:39   (localhost)

md       ttysU   Dec  2 08:45   (muller)

jac      ttysa   Dec  3 18:18   (localhost)

eichsted ttysb   Dec  3 23:21   (pc1)

sweett   ttysc   Dec  3 22:40   (dov)

"big.output" 40 lines, 1659 characters

Because I have only a 25-line display and the output is 40 lines long (you can see that on the status line at the bottom), there is more information in this file than the screen can display at once.

To see the next screenful, hold down the Ctrl key, press the F key, and then let both go. In future, when I indicate Ctrl+F that's what I mean you should do.

eichsted ttysb   Dec  3 23:21   (pc1)

sweett   ttysc   Dec  3 22:40   (dov)

wellman  ttysd   Dec  3 23:01   (dov)

tuttleno ttyse   Dec  3 23:03   (indyvax)

wu       ttysf   Dec  3 23:10   (term01)

daurismj ttysg   Dec  3 23:10   (dov)

cs414    ttysh   Dec  3 23:12   (xds)

cq       ttysi   Dec  3 23:13   (expert)

cdemmert ttysk   Dec  3 22:37   (xsun22)

jrlee    ttysn   Dec  3 22:53   (mac1)

fitzgejs ttyso   Dec  3 23:18   (dov)

doerrhb  ttysp   Dec  3 23:20   (dov)

cdemmert ttysq   Dec  3 23:00   (xsun22)

frazierw ttysr   Dec  3 23:01   (dov)

buckeye  ttyss   Dec  3 23:20   (mac2)

mtaylor  ttyst   Dec  3 23:22   (dov)

look     ttysu   Dec  3 23:12   (age)

janitor  ttysw   Dec  3 18:29   (age)

ajones   ttysx   Dec  3 23:23   (rass)

~

~

~

~

Notice that the entire screen was rewritten, and that the familiar tilde characters have popped up again to indicate the end of the file.

By default, vi has a two-line overlap when you move from screen to screen. If you look carefully, you can see that both eichsted and sweett show up on both screens of data. This doesn't mean that they appear twice in the file; rather, vi is trying to help you not get lost while you wander through the file.

Now, what do you think will happen if you press Ctrl+U?

leungtc  ttys0   Nov 28 15:11   (gold)

chinese  ttys2   Dec  3 22:53   (excalibur)

cdemmert ttys5   Dec  3 23:00   (mentor)

yuenca   ttys6   Dec  3 23:00   (mentor)

janitor  ttys7   Dec  3 18:18   (age)

mathisbp ttys8   Dec  3 23:17   (dov)

janitor  ttys9   Dec  3 18:18   (age)

cs541    ttysC   Dec  2 15:16   (solaria)

yansong  ttysL   Dec  1 14:44   (math)

mdps     ttysO   Nov 30 19:39   (localhost)

md       ttysU   Dec  2 08:45   (muller)

jac      ttysa   Dec  3 18:18   (localhost)

eichsted ttysb   Dec  3 23:21   (pc1)

sweett   ttysc   Dec  3 22:40   (dov)

wellman  ttysd   Dec  3 23:01   (dov)

tuttleno ttyse   Dec  3 23:03   (indyvax)

wu       ttysf   Dec  3 23:10   (term01)

daurismj ttysg   Dec  3 23:10   (dov)

cs414    ttysh   Dec  3 23:12   (xds)

cq       ttysi   Dec  3 23:13   (expert)

cdemmert ttysk   Dec  3 22:37   (xsun22)

jrlee    ttysn   Dec  3 22:53   (mac1)

fitzgejs ttyso   Dec  3 23:18   (dov)

The command has moved you up half a screen. Notice where eichsted and sweett are now. Instead of the text being replaced at once, as when you used Ctrl+F, the text was scrolled downward a line at a time, each new line being added as the program went along. The Ctrl+U command might work either way—one line or an entire screen at a time—for you.

Now it's time to try moving around in this file word by word. Find the w key on your keyboard and press it once to see what happens.

leungtc  ttys0   Nov 28 15:11   (gold)

chinese  ttys2   Dec  3 22:53   (excalibur)

cdemmert ttys5   Dec  3 23:00   (mentor)

Now press w six times more, noting that the cursor stops three times in the field to indicate what time the user logged into the system (15:11 in this listing). Now your cursor should be sitting on the parenthesized field:

leungtc  ttys0   Nov 28 15:11   (gold)

chinese  ttys2   Dec  3 22:53   (excalibur)

cdemmert ttys5   Dec  3 23:00   (mentor)

It's time to move backward. Press b a few times; your cursor moves backward to the beginning of each word.

What happens if you try to move backward but you're already on the first word of the line, or you try to move forward but you're already on the last word?

Using the various keys you've learned, move back to the beginning of the line beginning with leungtc, which you used in the last exercise:

leungtc  ttys0   Nov 28 15:11   (gold)

chinese  ttys2   Dec  3 22:53   (excalibur)

cdemmert ttys5   Dec  3 23:00   (mentor)

This time press the uppercase letter W, rather than the lowercase w, to move through this line. Can you see the difference? Notice what happens when you hit the time field and the parenthesized words. Instead of pressing w seven times to move to the left parenthesis before gold, you can press W just five times.

Try moving backward using the B command. Notice that the B command differs from the b command the same way the W command differs from the w command.

Moving about forward and backward word by word, being able to move half screens or full screens at a time, and being able to zero in on specific spots with the h, j, k, and l cursor-motion keys give you quite a range of motion. Practice using these commands in various combinations to move your cursor to specific characters in your sample file.

Inserting Text into the File with i, a, o, and O

Being able to move around in a file is useful. The real function of an editor, however, is to enable you to easily add and remove—in editor parlance, insert and delete—information. The vi editor has a special insert mode, which you must use in order to add to the contents of the file. There are four different ways to shift into insert mode, and you will learn about all of them in this section.

The first way to switch to insert mode is to enter the letter i, which, mnemonically enough, inserts text into the file. The other commands that accomplish more or less the same thing are a, which appends text to the file; o, which opens up a line below the current line; and O, which opens up a line above the current line.

This time you want to start with a clean file, so quit from the big.output editing session and start vi again, this time specifying a nonexistent file called buckaroo:

% vi buckaroo

~

~

~

~

~

~

~

~

~

~

~

~

~

~

~

~

~

~

~

~

~

~

~

"buckaroo" [New file]

Notice that vi reminds you that this file doesn't exist; the bottom of the screen says New file instead of indicating the number of lines and characters.

Now it's time to try using insert mode. Press k once:

~

~

~

~

The system beeps at you because you haven't moved into insert mode yet, and k still has its command meaning of moving down a line (and of course, there isn't another line yet).

Press the i key to move into insert mode, and then press the k key again:

k_

~

~

~

There you go! You've added a character to the file.

Press the Backspace key, which will move the cursor over the letter k:

k

~

~

~

Now see what happens when you press Esc to leave insert mode and return to the vi command mode:

~

~

~

~

Notice that the k vanished when you pressed Esc. That's because vi only saves text you've entered to the left of or above the cursor, not the letter the cursor is resting on.

Now move back into insert mode by pressing i and enter a few sentences from a favorite book of mine:

"He's not even here," went the conservation.

"Banzai."

"Where is he?"

"At a hotpsial in El paso."

"What? Why werent' we informed? What's wrong with him?"_

~

~

NOTE: Movie buffs will perhaps recognize that this text comes from the book Buckaroo Banzai. The film The Adventures of Buckaroo Banzai Across the Eighth Dimension is based on this very fun book.

I've deliberately left some typing errors in the text here. Fixing them will demonstrate some important features of the vi editor. If you fixed them as you went along, that's okay, and if you added errors of your own, that's okay, too!

Press Esc to leave insert mode. Press Esc a second time to ensure that it worked; remember that vi beeps to remind you that you're already in command mode.

Now use the cursor motion keys (h, j, k, and l) to move the cursor to any point on the first line:

"He's not even here," went the conservation.

"Banzai."

"Where is he?"

"At the hotpsial in El paso."

"What? Why werent' we informed? What's wrong with him?"

~

~

It turns out that there's a line of dialogue missing between the line you're on and "Banzai." One way to enter the line would be to move to the beginning of the line "Banzai.", insert the new text, and press Enter before pressing Esc to quit insert mode. But vi has a special command—o—to open a line immediately below the current line for inserting text. Press o on your keyboard and follow along:

"He's not even here," went the conservation.

_

"Banzai."

"Where is he?"

"At the hotpsial in El paso."

"What? Why werent' we informed? What's wrong with him?"

~

~

Now type the missing text:

"He's not even here," went the conservation.

"Who?"_

"Banzai."

"Where is he?"

"At the hotpsial in El paso."

"What? Why werent' we informed? What's wrong with him?"

~

~

That's it. Press Esc to return to command mode.

The problem with the snippet of dialogue you're using is that there's no way to figure out who is talking. Adding a line above this dialogue helps identify the speakers. Again, use cursor motion keys to place the cursor on the top line:

"He's not _even here," went the conservation.

"Banzai."

"Where is he?"

"At the hotpsial in El paso."

"What? Why werent' we informed? What's wrong with him?"

~

~

Now you face a dilemma. You want to open up a line for new text, but you want the line to be above the current line, not below it. It happens that vi can do that, too. Instead of using the o command, use its big brother O instead. When you press O, here's what you see:

_

"He's not even here," went the conservation.

"Banzai."

"Where is he?"

"At the hotpsial in El paso."

"What? Why werent' we informed? What's wrong with him?"

~

~

Type the new sentence and press Esc.

I found myself stealing a peek at my own watch and overhead

General Catbird's 

aide give him the latest._

"He's not even here," went the conservation.

"Banzai."

"Where is he?"

"At the hotpsial in El paso."

"What? Why werent' we informed? What's wrong with him?"

~

~

Now the dialogue makes a bit more sense. The conversation, overheard by the narrator, takes place between the general and his aide.

There are a few words missing in one of the lines, so the next task is to insert them. Use the cursor keys to move the cursor to the fifth line, just after the word "Where":

I found myself stealing a peek at my own watch and overhead

General Catbird's

aide give him the latest.

"He's not even here," went the conservation.

"Banzai."

"Where_is he?"

"At the hotpsial in El paso."

"What? Why werent' we informed? What's wrong with him?"

~

~

At this juncture, you need to add the words "the hell" to make the sentence a bit stronger (and correct). You can use i to insert the text, but then you end up with a trailing space. Instead, you can add text immediately after the current cursor location by using the a key to append the information. When you press a, the cursor moves one character to the right:

I found myself stealing a peek at my own watch and overhead

General Catbird's 

aide give him the latest.

"He's not even here," went the conservation.

"Banzai."

"Where is he?"

"At the hotpsial in El paso."

"What? Why werent' we informed? What's wrong with him?"

~

~

Here's where vi can be difficult to use. You're in insert mode, but there's no way for you to know that. When you type the letters you want to add, the screen shows that they are appended. But what if you think you're in insert mode when you're actually in command mode? One trick you could use to ensure you're in insert mode is to press the command key a second time. If the letter "a" shows up in the text, simply backspace over it; now you know that you're in append mode. When you're done entering the new characters, and you're still in append mode, here's what your screen looks like:

I found myself stealing a peek at my own watch and overhead

General Catbird's 

aide give him the latest.

"He's not even here," went the conservation.

"Banzai."

"Where the hell is he?"

"At the hotpsial in El paso."

"What? Why werent' we informed? What's wrong with him?"

~

~

Notice that the cursor stayed on the "i" in "is" throughout this operation. Press Esc to return to command mode. Notice that the cursor finally hops off the "i" and moves left one character.

To differentiate between the i and a commands, remember that the insert command always adds the new information immediately before the cursor, whereas append adds the information immediately after the cursor.

With this in mind, try to fix the apostrophe problem in the word "werent'" on the last line. Move the cursor to the "n" in that word:

"Where the hell is he?"

"At the hotpsial in El paso."

"What? Why werent' we informed? What's wrong with him?"

~

Now, to put the apostrophe immediately after the current character, do you want to use the insert command (i) or the append command? If you said "Append," give yourself a pat on the back! Press a to append the apostrophe:

"Where the hell is he?"

"At the hotpsial in El paso."

"What? Why werent' we informed? What's wrong with him?"

~

Press the ' key once and press Esc.

Quit vi. Use :q, and the program reminds you that you haven't saved your changes to this new file:

~

~

No write since last change (:quit! overrides)

To write the changes, you need a new command, so I'll give you a preview of a set of colon commands you will learn later in this chapter. Type : (the colon character), which moves the cursor to the bottom of the screen.

~

~

:_

Now press w to write out the file, and then press the Enter key:

~

~

"buckaroo" 8 lines, 271 characters

It's okay to leave vi now. Use :q to quit and you're safely back at the command prompt. A quick cat confirms that the tildes were not included in the file itself:

%

% cat buckaroo

I found myself stealing a peek at my own watch and overhead

General Catbird's

aide give him the latest.

"He's not even here," went the conservation.

"Banzai."

"Where the hell is he?"

"At the hotpsial in El paso."

"What? Why weren't' we informed? What's wrong with him?"

%

As you can tell, the vi editor is quite powerful, and it has a plethora of commands. Just moving about and inserting text, you have learned 24 commands, as summarized in Table 7.1.

Command


Meaning


0

Move to beginning of line.

$

Move to end of line.

a

Append text—move into insert mode after the current character.

^b

Back up one screen of text.

B

Back up one space-delimited word.

b

Back up one word.

Backspace

Move left one character.

^d

Move down half a page.

Esc

Leave insert mode, return to command mode.

^f

Move forward one screen of text.

h

Move left one character.

i

Insert text—move into insert mode before the current character.

j

Move down one line.

k

Move up one line.

l

Move right one character.

O

Open new line for insert above the current line.

o

Open new line for insert below the current line.

Enter

Move to beginning of next line.

^u

Move up half a page.

W

Move forward one space-delimited word.

w

Move forward one word.

:w

Write the edit buffer to the system.

:q

Quit vi and return to the UNIX prompt.

:q!

Quit vi and return to the system, throwing away any changes made to the file.


WARNING: In this table, I've introduced a simple shorthand notation that's worth explaining. UNIX users often use a caret followed by a character instead of the awkward Ctrl+c notation. Therefore, ^f has the same meaning as Ctrl+F. Expressing this operation as ^f does not change the way it's performed: you'd still press and hold down the Ctrl key and then press the lowercase F key. It's just a shorter notation.

You've already learned quite a few commands, but you've barely scratched the surface of the powerful vi command!

Deleting Text

You now have many of the pieces you need to work efficiently with the vi editor, to zip to any point in the file, or to add text wherever you like. Now you need to learn how to delete characters, words, and lines.

The simplest form of the delete command is the x command, which functions as though you are writing an X over a letter you don't want on a printed page: it deletes the character under the cursor. Press x five times and you delete five characters. Deleting a line of text this way can be quite tedious, so vi has some alternate commands. (Are you surprised?) One command that many vi users don't know about is the D, or delete through end of line, command. Wherever you are on a line, pressing D immediately deletes everything after the cursor to the end of that line of text.

If there's an uppercase D command, you can just bet there's a lowercase d command too. The d command is the first of a set of more sophisticated vi commands, which are followed by a second command that indicates what you'd like to do with the command. You already know that w and W move you forward a word in the file; they're known as addressing commands in vi. You can follow d with one of these addressing commands to specify what you would like to delete. For example, to delete a line, simply press dd.

Sometimes you might get a bit overzealous and delete more than you anticipated. That's not a problem—well, not too much of a problem—because vi remembers the state of the file prior to the most recent action taken. To undo a deletion (or insertion, for that matter), use the u command. To undo a line of changes, use the U command. Be aware that once you've moved off the line in question, the U command is unable to restore it!

Start vi again with the big.output file you used earlier:

leungtc  ttyrV   Dec  1 18:27   (magenta)

tuyinhwa ttyrX   Dec  3 22:38   (expert)

hollenst ttyrZ   Dec  3 22:14   (dov)

brandt   ttyrb   Nov 28 23:03   (age)

holmes   ttyrj   Dec  3 21:59   (age)

yuxi     ttyrn   Dec  1 14:19   (pc)

frodo    ttyro   Dec  3 22:01   (mentor)

labeck   ttyrt   Dec  3 22:02   (dov)

chenlx2  ttyru   Dec  3 21:53   (mentor)

leungtc  ttys0   Nov 28 15:11   (gold)

chinese  ttys2   Dec  3 22:53   (excalibur)

cdemmert ttys5   Dec  3 23:00   (mentor)

yuenca   ttys6   Dec  3 23:00   (mentor)

janitor  ttys7   Dec  3 18:18   (age)

mathisbp ttys8   Dec  3 23:17   (dov)

janitor  ttys9   Dec  3 18:18   (age)

cs541    ttysC   Dec  2 15:16   (solaria)

yansong  ttysL   Dec  1 14:44   (math)

mdps     ttysO   Nov 30 19:39   (localhost)

md       ttysU   Dec  2 08:45   (muller)

jac      ttysa   Dec  3 18:18   (localhost)

eichsted ttysb   Dec  3 23:21   (pc1)

sweett   ttysc   Dec  3 22:40   (dov)

"big.output" 40 lines, 1659 characters

Press the x key a few times to delete a few characters from the beginning of the file:

gtc  ttyrV   Dec  1 18:27   (magenta)

tuyinhwa ttyrX   Dec  3 22:38   (expert)

hollenst ttyrZ   Dec  3 22:14   (dov)

brandt   ttyrb   Nov 28 23:03   (age)

holmes   ttyrj   Dec  3 21:59   (age)

Now press u to undo the last deletion:

ngtc  ttyrV   Dec  1 18:27   (magenta)

tuyinhwa ttyrX   Dec  3 22:38   (expert)

hollenst ttyrZ   Dec  3 22:14   (dov)

brandt   ttyrb   Nov 28 23:03   (age)

holmes   ttyrj   Dec  3 21:59   (age)

If you press u again, what do you think will happen?

gtc  ttyrV   Dec  1 18:27   (magenta)

tuyinhwa ttyrX   Dec  3 22:38   (expert)

hollenst ttyrZ   Dec  3 22:14   (dov)

brandt   ttyrb   Nov 28 23:03   (age)

holmes   ttyrj   Dec  3 21:59   (age)

The undo command alternates between the last command having happened or not having happened. To explain it a bit better, the undo command is an action unto itself, so the second time you press u, you're undoing the undo command that you just requested. Press the u key a few more times if you need to convince yourself that this is the case.

It's time to make some bigger changes to the file. Press dw twice to delete the current word and the next word in the file. It should look something like this after the first dw:

ttyrV   Dec  1 18:27   (magenta)

tuyinhwa ttyrX   Dec  3 22:38   (expert)

hollenst ttyrZ   Dec  3 22:14   (dov)

brandt   ttyrb   Nov 28 23:03   (age)

holmes   ttyrj   Dec  3 21:59   (age)

Then it should look like this after the second dw:

Dec  1 18:27   (magenta)

tuyinhwa ttyrX   Dec  3 22:38   (expert)

hollenst ttyrZ   Dec  3 22:14   (dov)

brandt   ttyrb   Nov 28 23:03   (age)

holmes   ttyrj   Dec  3 21:59   (age)

Press u. You see that you can only undo the most recent command. At this point, though, because you haven't moved from the line you're editing, the U, or undo a line of changes, command will restore the line to its original splendor:

leungtc  ttyrV   Dec  1 18:27   (magenta)

tuyinhwa ttyrX   Dec  3 22:38   (expert)

hollenst ttyrZ   Dec  3 22:14   (dov)

brandt   ttyrb   Nov 28 23:03   (age)

holmes   ttyrj   Dec  3 21:59   (age)

Well, in the end, you really don't want to see some of these folk. Fortunately, you can delete lines with the dd command. What if I want to delete the entries for chinese and janitor, both of which are visible on this screen?

The first step is to use the cursor keys to move down to any place on the line for the chinese account, about halfway down the screen:

chenlx2  ttyru   Dec  3 21:53   (mentor)

leungtc  ttys0   Nov 28 15:11   (gold)

chinese  ttys2   Dec  3 22:53   (excalibur)

cdemmert ttys5   Dec  3 23:00   (mentor)

yuenca   ttys6   Dec  3 23:00   (mentor)

janitor  ttys7   Dec  3 18:18   (age)

mathisbp ttys8   Dec  3 23:17   (dov)

If your cursor isn't somewhere in the middle of this line, move it so that you too are not at an edge.

Instead of removing this line completely, perhaps you'd rather just remove the date, time, and name of the system (in parentheses) instead. To accomplish this, you don't need to press dw a bunch of times, or even x a lot of times, but rather just D to delete through the end of the line:

chenlx2  ttyru   Dec  3 21:53   (mentor)

leungtc  ttys0   Nov 28 15:11   (gold)

chinese  ttys2  _

cdemmert ttys5   Dec  3 23:00   (mentor)

yuenca   ttys6   Dec  3 23:00   (mentor)

janitor  ttys7   Dec  3 18:18   (age)

mathisbp ttys8   Dec  3 23:17   (dov)

Oh, that's not quite what you wanted to do. No problem, the undo command can fix it. Simply pressing the u key restores the text you deleted:

chenlx2  ttyru   Dec  3 21:53   (mentor)

leungtc  ttys0   Nov 28 15:11   (gold)

chinese  ttys2   Dec  3 22:53   (excalibur)

cdemmert ttys5   Dec  3 23:00   (mentor)

yuenca   ttys6   Dec  3 23:00   (mentor)

janitor  ttys7   Dec  3 18:18   (age)

mathisbp ttys8   Dec  3 23:17   (dov)

The problem is that you used the wrong command to delete the two entries chinese and janitor from the file. Instead of using the D command, you should use dd. Pressing dd once has these results:

Dec  1 18:27    (magenta)

tuyinhwa ttyrX   Dec  3 22:38   (expert)

hollenst ttyrZ   Dec  3 22:14   (dov)

brandt   ttyrb   Nov 28 23:03   (age)

holmes   ttyrj   Dec  3 21:59   (age)

yuxi     ttyrn   Dec  1 14:19   (pc)

frodo    ttyro   Dec  3 22:01   (mentor)

labeck   ttyrt   Dec  3 22:02   (dov)

chenlx2  ttyru   Dec  3 21:53   (mentor)

leungtc  ttys0   Nov 28 15:11   (gold)

cdemmert ttys5   Dec  3 23:00   (mentor)

yuenca   ttys6   Dec  3 23:00   (mentor)

janitor  ttys7   Dec  3 18:18   (age)

mathisbp ttys8   Dec  3 23:17   (dov)

janitor  ttys9   Dec  3 18:18   (age)

cs541    ttysC   Dec  2 15:16   (solaria)

yansong  ttysL   Dec  1 14:44   (math)

mdps     ttysO   Nov 30 19:39   (localhost)

md       ttysU   Dec  2 08:45   (muller)

jac      ttysa   Dec  3 18:18   (localhost)

eichsted ttysb   Dec  3 23:21   (pc1)

sweett   ttysc   Dec  3 22:40   (dov)

wellman  ttysd   Dec  3 23:01   (dov)

Notice that a new line of information has been pulled onto the screen at the bottom to replace the blank line that you removed. If you try using the u command now, what happens? You're almost done. A few presses of the Enter key and you're down to the entry for the janitor account. Using dd removes that line too:

Dec  1 18:27    (magenta)

tuyinhwa ttyrX   Dec  3 22:38   (expert)

hollenst ttyrZ   Dec  3 22:14   (dov)

brandt   ttyrb   Nov 28 23:03   (age)

holmes   ttyrj   Dec  3 21:59   (age)

yuxi     ttyrn   Dec  1 14:19   (pc)

frodo    ttyro   Dec  3 22:01   (mentor)

labeck   ttyrt   Dec  3 22:02   (dov)

chenlx2  ttyru   Dec  3 21:53   (mentor)

leungtc  ttys0   Nov 28 15:11   (gold)

cdemmert ttys5   Dec  3 23:00   (mentor)

yuenca   ttys6   Dec  3 23:00   (mentor)

mathisbp ttys8   Dec  3 23:17   (dov)

janitor  ttys9   Dec  3 18:18   (age)

cs541    ttysC   Dec  2 15:16   (solaria)

yansong  ttysL   Dec  1 14:44   (math)

mdps     ttysO   Nov 30 19:39   (localhost)

md       ttysU   Dec  2 08:45   (muller)

jac      ttysa   Dec  3 18:18   (localhost)

eichsted ttysb   Dec  3 23:21   (pc1)

sweett   ttysc   Dec  3 22:40   (dov)

wellman  ttysd   Dec  3 23:01   (dov)

tuttleno ttyse   Dec  3 23:03   (indyvax)

Each line below the one deleted moves up a line to fill in the blank space, and a new line, for tuttleno, moves up from the following screen.

Now you want to return to the buckaroo file to remedy some of the horrendous typographic errors! It doesn't matter whether you save the changes you've just made to the file, so use :q! to quit, discarding these edit changes to the big.output file. Entering vi buckaroo starts vi again:

I found myself stealing a peek at my own watch and overhead

General Catbird's

aide give him the latest.

"He's not even here," went the conservation.

"Banzai."

"Where the hell is he?"

"At the hotpsial in El paso."

"What? Why weren't' we informed? What's wrong with him?"

~

~

~

~

~

~

~

~

~

~

~

~

~

~

~

"buckaroo" 8 lines, 271 characters

There are a few fixes you can make in short order. The first is to change "conservation" to "conversation" on the third line. To move there, press the Return key twice and then use W to zip forward until the cursor is at the first letter of the word you're editing:

I found myself stealing a peek at my own watch and overhead

General Catbird's

aide give him the latest.

"He's not even here," went the conservation.

"Banzai."

"Where the hell is he?"

Then use the dw command:

I found myself stealing a peek at my own watch and overhead

General Catbird's

aide give him the latest.

"He's not even here," went the .

"Banzai."

"Where the hell is he?"

Now enter insert mode by pressing i and type in the correct spelling of the word "conversation." Then press Esc:

I found myself stealing a peek at my own watch and overhead

General Catbird's

aide give him the latest.

"He's not even here," went the conversation.

"Banzai."

"Where the hell is he?"

That's one fix. Now move down a few lines to fix the atrocious misspelling of "hospital":

"Banzai."

"Where the hell is he?"

"At the hotpsial in El paso."

"What? Why weren't' we informed? What's wrong with him?"

~

Again, use dw to delete the word, then i to enter insert mode. Type "hospital" and press Esc, and all is well on the line:

"Banzai."

"Where the hell is he?"

"At the hospital in El paso."

"What? Why weren't' we informed? What's wrong with him?"

~

Well, almost all is well. The first letter of "Paso" needs to be capitalized. Move to it by pressing w:

"Banzai."

"Where the hell is he?"

"At the hospital in El paso."

"What? Why weren't' we informed? What's wrong with him?"

~

It's time for a secret vi expert command! Instead of pressing x to delete the letter, i to enter insert mode, P as the correct letter, and Esc to return to command mode, there's a much faster way to transpose case: the ~ command. Press the ~ character once, and here's what happens:

"Banzai."

"Where the hell is he?"

"At the hospital in El Paso."

"What? Why weren't' we informed? What's wrong with him?"

~

Cool, isn't it? Back up to the beginning of the word again, using the h command, and press ~ a few times to see what happens. Notice that each time you press ~, the character's case switches (transposes) and the cursor moves to the next character. Press ~ four times and you should end up with this:

"Banzai."

"Where the hell is he?"

"At the hospital in El pASO."

"What? Why weren't' we informed? What's wrong with him?"

~

Back up to the beginning of the word and press ~ four more times until the word is correct.

One more slight change and the file is fixed! Move to the last line of the file, to the extra apostrophe in the word "weren't'," and use the x key to delete the offending character. The screen should now look like this:

I found myself stealing a peek at my own watch and overhead

General Catbird's

aide give him the latest.

"He's not even here," went the conversation.

"Banzai."

"Where the hell is he?"

"At the hospital in El Paso."

"What? Why weren't we informed? What's wrong with him?"

~

~

~

~

~

~

~

~

~

~

~

~

~

~

~

That looks great! It's time to save it for posterity. Use :wq, a shortcut that has vi write out the changes, and then immediately quit the program:

~

~

~

"buckaroo" 8 lines, 270 characters

%

Not only have you learned about the variety of deletion options in vi, but you have also learned a few simple shortcut commands: ~, which transposes case, and :wq, which writes out the changes and quits the program all in one step.

You should feel pleased; you're now a productive and knowledgeable vi user, and you can modify files, making easy or tough changes. Go back to your system and experiment further, modifying some of the other files. Be careful, though, not to make changes in any of your dot files (for example, .cshrc), lest you cause trouble that would be difficult to fix!

Searching within a File

With the addition of two more capabilities, you'll be ready to face down any vi expert, demonstrating your skill and knowledge of the editor. Much more importantly, you'll be able to really fly through files, moving immediately to the information you desire.

The two new capabilities are for finding specific words or phrases in a file and for moving to specific lines in a file. Similar to searching for patterns in more and page, /pattern searches forward in the file for a specified pattern, and ?pattern searches backward for the specified pattern. To repeat the previous search, use the n command to tell vi to search again, in the same direction, for the same pattern.

You can easily move to any specific line in a file using the G, or go to line, command. If you press a number before you press G, the cursor will move to that line in the file. If you press G without a line number, the cursor will zip you to the very last line of the file by default.

Start vi again with the big.output file:

leungtc  ttyrV   Dec  1 18:27   (magenta)

tuyinhwa ttyrX   Dec  3 22:38   (expert)

hollenst ttyrZ   Dec  3 22:14   (dov)

brandt   ttyrb   Nov 28 23:03   (age)

holmes   ttyrj   Dec  3 21:59   (age)

yuxi     ttyrn   Dec  1 14:19   (pc)

frodo    ttyro   Dec  3 22:01   (mentor)

labeck   ttyrt   Dec  3 22:02   (dov)

chenlx2  ttyru   Dec  3 21:53   (mentor)

leungtc  ttys0   Nov 28 15:11   (gold)

chinese  ttys2   Dec  3 22:53   (excalibur)

cdemmert ttys5   Dec  3 23:00   (mentor)

yuenca   ttys6   Dec  3 23:00   (mentor)

janitor  ttys7   Dec  3 18:18   (age)

mathisbp ttys8   Dec  3 23:17   (dov)

janitor  ttys9   Dec  3 18:18   (age)

cs541    ttysC   Dec  2 15:16   (solaria)

yansong  ttysL   Dec  1 14:44   (math)

mdps     ttysO   Nov 30 19:39   (localhost)

md       ttysU   Dec  2 08:45   (muller)

jac      ttysa   Dec  3 18:18   (localhost)

eichsted ttysb   Dec  3 23:21   (pc1)

sweett   ttysc   Dec  3 22:40   (dov)

"big.output" 40 lines, 1659 characters

Remember that you used :q! to quit earlier, so your changes were not retained.

To move to the very last line of the file, press G once:

cdemmert ttysk   Dec  3 22:37   (xsun)

jrlee    ttysn   Dec  3 22:53   (mac1)

fitzgejs ttyso   Dec  3 23:18   (dov)

doerrhb  ttysp   Dec  3 23:20   (dov)

cdemmert ttysq   Dec  3 23:00   (xsun)

frazierw ttysr   Dec  3 23:01   (dov)

buckeye  ttyss   Dec  3 23:20   (mac2)

mtaylor  ttyst   Dec  3 23:22   (dov)

look     ttysu   Dec  3 23:12   (age)

janitor  ttysw   Dec  3 18:29   (age)

ajones   ttysx   Dec  3 23:23   (rassilon)

~

~

~

~

~

~

~

~

~

~

~

~

To move to the third line of the file, press 3 followed by G:

leungtc  ttyrV   Dec  1 18:27   (magenta)

tuyinhwa ttyrX   Dec  3 22:38   (expert)

hollenst ttyrZ   Dec  3 22:14   (dov)

brandt   ttyrb   Nov 28 23:03   (age)

holmes   ttyrj   Dec  3 21:59   (age)

yuxi     ttyrn   Dec  1 14:19   (pc)

frodo    ttyro   Dec  3 22:01   (mentor)

labeck   ttyrt   Dec  3 22:02   (dov)

chenlx2  ttyru   Dec  3 21:53   (mentor)

leungtc  ttys0   Nov 28 15:11   (gold)

chinese  ttys2   Dec  3 22:53   (excalibur)

cdemmert ttys5   Dec  3 23:00   (mentor)

yuenca   ttys6   Dec  3 23:00   (mentor)

janitor  ttys7   Dec  3 18:18   (age)

mathisbp ttys8   Dec  3 23:17   (dov)

janitor  ttys9   Dec  3 18:18   (age)

cs541    ttysC   Dec  2 15:16   (solaria)

yansong  ttysL   Dec  1 14:44   (math)

mdps     ttysO   Nov 30 19:39   (localhost)

md       ttysU   Dec  2 08:45   (muller)

jac      ttysa   Dec  3 18:18   (localhost)

eichsted ttysb   Dec  3 23:21   (pc1)

sweett   ttysc   Dec  3 22:40   (dov)

Notice that the cursor is on the third line of the file.

Now it's time to search. From your previous travels in this file, you know that the very last line is for the account ajones, but instead of using G to move there directly, you can search for the specified pattern by using the / search command.

Pressing / immediately moves the cursor to the bottom of the screen:

md       ttysU   Dec  2 08:45   (mueller)

jac      ttysa   Dec  3 18:18   (localhost)

eichsted ttysb   Dec  3 23:21   (pc1)

sweett   ttysc   Dec  3 22:40   (dov)

/_

Now you can type in the pattern ajones:

md       ttysU   Dec  2 08:45   (mueller)

jac      ttysa   Dec  3 18:18   (localhost)

eichsted ttysb   Dec  3 23:21   (pc1)

sweett   ttysc   Dec  3 22:40   (dov)

/ajones_

When you press Return, vi spins through the file and moves you to the first line it finds that contains the specified pattern:

cdemmert ttysk   Dec  3 22:37   (xsun)

jrlee    ttysn   Dec  3 22:53   (mac1)

fitzgejs ttyso   Dec  3 23:18   (dov)

doerrhb  ttysp   Dec  3 23:20   (dov)

cdemmert ttysq   Dec  3 23:00   (xsun)

frazierw ttysr   Dec  3 23:01   (dov)

buckeye  ttyss   Dec  3 23:20   (mac2)

mtaylor  ttyst   Dec  3 23:22   (dov)

look     ttysu   Dec  3 23:12   (age)

janitor  ttysw   Dec  3 18:29   (age)

ajones   ttysx   Dec  3 23:23   (rassilon)

~

~

~

~

~

~

~

~

~

~

~

~

If you press n to search for this pattern again, a slash appears at the very bottom line to show that vi understood your request. But the cursor stays exactly where it is, which indicates that this is the only occurrence of the pattern in this file.

You notice that the account janitor has all sorts of sessions running. To search backward for occurrences of their account, use the ? command:

~

~

?janitor_

The first search moves the cursor up one line, which leaves the screen looking almost the same:

cdemmert ttysk   Dec  3 22:37   (xsun)

jrlee    ttysn   Dec  3 22:53   (mac1)

fitzgejs ttyso   Dec  3 23:18   (dov)

doerrhb  ttysp   Dec  3 23:20   (dov)

cdemmert ttysq   Dec  3 23:00   (xsun)

frazierw ttysr   Dec  3 23:01   (dov)

buckeye  ttyss   Dec  3 23:20   (mac2)

mtaylor  ttyst   Dec  3 23:22   (dov)

look     ttysu   Dec  3 23:12   (age)

janitor  ttysw   Dec  3 18:29   (age)

ajones   ttysx   Dec  3 23:23   (rassilon)

~

~

~

~

~

~

~

~

~

~

~

~

?janitor

Here's where n, or next search, can come in handy. If you press n this time and there is another occurrence of the pattern in the file, vi moves you directly to the match:

yuxi     ttyrn   Dec  1 14:19   (pc)

frodo    ttyro   Dec  3 22:01   (mentor)

labeck   ttyrt   Dec  3 22:02   (dov)

chenlx2  ttyru   Dec  3 21:53   (mentor)

leungtc  ttys0   Nov 28 15:11   (gold)

chinese  ttys2   Dec  3 22:53   (excalibur)

cdemmert ttys5   Dec  3 23:00   (mentor)

yuenca   ttys6   Dec  3 23:00   (mentor)

janitor  ttys7   Dec  3 18:18   (age)

mathisbp ttys8   Dec  3 23:17   (dov)

janitor  ttys9   Dec  3 18:18   (age)

cs541    ttysC   Dec  2 15:16   (solaria)

yansong  ttysL   Dec  1 14:44   (math)

mdps     ttysO   Nov 30 19:39   (localhost)

md       ttysU   Dec  2 08:45   (muller)

jac      ttysa   Dec  3 18:18   (localhost)

eichsted ttysb   Dec  3 23:21   (pc1)

sweett   ttysc   Dec  3 22:40   (dov)

wellman  ttysd   Dec  3 23:01   (dov)

tuttleno ttyse   Dec  3 23:03   (indyvax)

wu       ttysf   Dec  3 23:10   (term01)

daurismj ttysg   Dec  3 23:10   (dov)

cs414    ttysh   Dec  3 23:12   (xds)

When you're done, quit vi by using :q.

There are not dozens, but hundreds of commands in vi. Rather than overwhelm you with all of them, even in a table, I have opted instead to work with the most basic and important commands.

How to Start vi Correctly

The vi command wouldn't be part of UNIX if it didn't have some startup options available, but there really are only two worth mentioning. The -R flag sets up vi as a read-only file to ensure that you don't accidentally modify a file. The second option doesn't start with a hyphen, but with a plus sign: any command following the plus sign is used as an initial command to the program. This is more useful than it may sound. The command vi +$ sample, for example, starts the editor at the bottom of the file sample, and vi +17 sample starts the editor on the 17th line of sample.

First, this is the read-only format:

% vi -R buckaroo

I found myself stealing a peek at my own watch and overhead

General Catbird's 

aide give him the latest.

"He's not even here," went the conversation.

"Banzai."

"Where the hell is he?"

"At the hospital in El Paso."

"What? Why weren't we informed? What's wrong with him?"

~

~

~

~

~

~

~

~

~

~

~

~

~

~

~

"buckaroo" [Read only] 8 lines, 270 characters

Notice the addition of the [Read only] message on the status line. You can edit the file, but if you try to save the edits with :w, you will see this:

~

~

"buckaroo" File is read only

Quit vi with :q!.

Next, recall that janitor occurs in many places in the big.output file. Start vi on the file line that contains the pattern janitor in the file:

% vi +/janitor big.output

brandt   ttyrb   Nov 28 23:03   (age)

holmes   ttyrj   Dec  3 21:59   (age)

yuxi     ttyrn   Dec  1 14:19   (pc)

frodo    ttyro   Dec  3 22:01   (mentor)

labeck   ttyrt   Dec  3 22:02   (dov)

chenlx2  ttyru   Dec  3 21:53   (mentor)

leungtc  ttys0   Nov 28 15:11   (gold)

chinese  ttys2   Dec  3 22:53   (excalibur)

cdemmert ttys5   Dec  3 23:00   (mentor)

yuenca   ttys6   Dec  3 23:00   (mentor)

janitor  ttys7   Dec  3 18:18   (age)

mathisbp ttys8   Dec  3 23:17   (dov)

janitor  ttys9   Dec  3 18:18   (age)

cs541    ttysC   Dec  2 15:16   (solaria)

yansong  ttysL   Dec  1 14:44   (math)

mdps     ttysO   Nov 30 19:39   (localhost)

md       ttysU   Dec  2 08:45   (muller)

jac      ttysa   Dec  3 18:18   (localhost)

eichsted ttysb   Dec  3 23:21   (pc1)

sweett   ttysc   Dec  3 22:40   (dov)

wellman  ttysd   Dec  3 23:01   (dov)

tuttleno ttyse   Dec  3 23:03   (indyvax)

wu       ttysf   Dec  3 23:10   (term01)

"big.output" 40 lines, 1659 characters

This time notice where the cursor is sitting.

Finally, launch vi with the cursor on the third line of the file buckaroo:

% vi +3 buckaroo

I found myself stealing a peek at my own watch and overhead

General Catbird's

aide give him the latest.

"He's not even here," went the conversation.

"Banzai."

"Where the hell is he?"

"At the hospital in El Paso."

"What? Why weren't we informed? What's wrong with him?"

~

~

~

~

~

~

~

~

~

~

~

~

~

~

~

"buckaroo" 8 lines, 270 characters

Again, notice where the cursor rests.

At times it can be helpful to know these two starting options. In particular, I often use +/pattern to start the editor at a specific pattern, but you can use vi for years without ever knowing more than just the name of the command itself.

The Key Colon Commands in vi

Without too much explanation, you have learned a few colon commands, commands that begin with a colon. The colon immediately zooms the cursor to the bottom of the screen for further input. These commands are actually a subset of quite a large range of commands, all part of the ex editor that lives inside the vi visual interface. (That's why vi is known as an interface to an editor, rather than an editor itself.)

The colon commands that are most helpful are :w, which writes the buffer back to the system; :w filename, which writes the buffer to the specified file; :q, which quits the editor; :q!, which quits regardless of whether any changes have occurred; :r filename, which reads another file into the editor; :e filename, which switches to the specified file; and :n, which moves to the next file in a list of files.

Start vi again, this time specifying more than one file on the command line; vi quickly indicates that you want to edit more than one file:

% vi buckaroo big.output

2 files to edit.

Then it clears the screen and shows you the first file:

I found myself stealing a peek at my own watch and overhead

General Catbird's 

aide give him the latest.

"He's not even here," went the conversation.

"Banzai."

"Where the hell is he?"

"At the hospital in El Paso."

"What? Why weren't we informed? What's wrong with him?"

~

~

~

~

~

~

~

~

~

~

~

~

~

~

~

"buckaroo" 8 lines, 270 characters

Using :w results in this:

~

~

~

"buckaroo" 8 lines, 270 characters

Instead, try writing to a different file, using :w newfile:

~

~

:w newfile_

When you press Return, you see this:

~

~

"newfile" [New file] 8 lines, 270 characters

Now pay attention to where the cursor is in the file. The :r, or read file, command always includes the contents of the file below the current line. Just before you press Return, then, here's what your screen looks like:

I found myself stealing a peek at my own watch and overhead

General Catbird's

aide give him the latest.

"He's not even here," went the conversation.

"Banzai."

"Where the hell is he?"

"At the hospital in El Paso."

"What? Why weren't we informed? What's wrong with him?"

~

~

~

~

~

~

~

~

~

~

~

~

~

~

~

:r newfile_

Pressing Return yields this:

I found myself stealing a peek at my own watch and overhead

General Catbird's

I found myself stealing a peek at my own watch and overhead

General Catbird's

aide give him the latest.

"He's not even here," went the conversation.

"Banzai."

"Where the hell is he?"

"At the hospital in El Paso."

"What? Why weren't we informed? What's wrong with him?"

aide give him the latest.

"He's not even here," went the conversation.

"Banzai."

"Where the hell is he?"

"At the hospital in El Paso."

"What? Why weren't we informed? What's wrong with him?"

~

~

~

~

~

~

~

This can be a helpful way to include one file within another, or to build a file that contains lots of other files.

Now that you've garbled the file, save it to a new file, buckaroo.confused:

~

~

:w buckaroo.confused_

Press Return:

~

~

"buckaroo.confused" [New file] 16 lines, 540 characters

Now it's time to move to the second file in the list of files given to vi at startup. To do this, I use the :n, or next file, command:

~

~

:n_

Pressing Return results in the next file being brought into the editor to replace the text removed earlier:

leungtc  ttyrV   Dec  1 18:27   (magenta)

tuyinhwa ttyrX   Dec  3 22:38   (expert)

hollenst ttyrZ   Dec  3 22:14   (dov)

brandt   ttyrb   Nov 28 23:03   (age)

holmes   ttyrj   Dec  3 21:59   (age)

yuxi     ttyrn   Dec  1 14:19   (pc)

frodo    ttyro   Dec  3 22:01   (mentor)

labeck   ttyrt   Dec  3 22:02   (dov)

chenlx2  ttyru   Dec  3 21:53   (mentor)

leungtc  ttys0   Nov 28 15:11   (gold)

chinese  ttys2   Dec  3 22:53   (excalibur)

cdemmert ttys5   Dec  3 23:00   (mentor)

yuenca   ttys6   Dec  3 23:00   (mentor)

janitor  ttys7   Dec  3 18:18   (age)

mathisbp ttys8   Dec  3 23:17   (dov)

janitor  ttys9   Dec  3 18:18   (age)

cs541    ttysC   Dec  2 15:16   (solaria)

yansong  ttysL   Dec  1 14:44   (math)

mdps     ttysO   Nov 30 19:39   (localhost)

md       ttysU   Dec  2 08:45   (muller)

jac      ttysa   Dec  3 18:18   (localhost)

eichsted ttysb   Dec  3 23:21   (pc1)

sweett   ttysc   Dec  3 22:40   (dov)

"big.output" 40 lines, 1659 characters

In the middle of working on this, you suddenly realize that you need to make a slight change to the recently saved buckaroo.confused file. That's where the :e command comes in handy. Using it, you can switch to any other file:

~

~

:e buckaroo.confused_

Press Return:

I found myself stealing a peek at my own watch and overhead

General Catbird's

I found myself stealing a peek at my own watch and overhead

General Catbird's

aide give him the latest.

"He's not even here," went the conversation.

"Banzai."

"Where the hell is he?"

"At the hospital in El Paso."

"What? Why weren't we informed? What's wrong with him?"

aide give him the latest.

"He's not even here," went the conversation.

"Banzai."

"Where the hell is he?"

"At the hospital in El Paso."

"What? Why weren't we informed? What's wrong with him?"

~

~

~

~

~

~

~

"buckaroo.confused" 16 lines, 540 characters

Table 7.2 summarizes the basic vi commands you learned in this section.

Command


Meaning


0

Move to beginning of line.

$

Move to end of line.

/pattern

Search forward for the next line using a specified pattern.

?pattern

Search backward for the next line using a specified pattern.

a

Append text—move into insert mode after the current character.

^b

Back up one screen of text.

B

Back up one space-delimited word.

b

Back up one word.

Backspace

Move left one character.

^d

Move down half a page.

D

Delete through end of line.

d

Delete—dw = delete word, dd = delete line.

Esc

Leave insert mode, return to command mode.

^f

Move forward one screen of text.

G

Go to the last line of the file.

nG

Go to the nth line of the file.

h

Move left one character.

i

Insert text—move into insert mode before the current character.

j

Move down one line.

k

Move up one line.

l

Move right one character.

n

Repeat last search.

O

Open new line for insert above the current line.

o

Open new line for insert below the current line.

Return

Move to beginning of next line.

^u

Move up half a page.

U

Undo—replace current line if changed.

u

Undo the last change made to the file.

W

Move forward one space-delimited word.

w

Move forward one word.

x

Delete a single character.

:e file

Edit a specified file without leaving vi.

:n

Move to the next file in the file list.

:q

Quit vi and return to the UNIX prompt.

:q!

Quit vi and return to the system, throwing away any changes made to the file.

:r file

Read the contents of a specified file, including it in the current edit buffer.

:w file

Write the contents of the buffer to a specified file.

:w

Write the edit buffer to the system.

Advanced vi Tricks, Tools, and Techniques

In the last section you learned some fifty vi commands, which enable you to easily move about in files, insert text, delete other text, search for specific patterns, and move from file to file without leaving the program. This section expands your expertise by showing you some more powerful vi commands.

To be honest, you can do fine in vi without ever reading this section. You already know how to insert and delete text, save or quit without saving, and search for particular patterns, even from the command line as you start vi for the first time! On the other hand, vi is like any other complex topic. The more you're willing to study and learn, the more the program will bow to your needs. This means you can accomplish a wider variety of different tasks on a daily basis.

The Change and Replace Commands

In the last section, you fixed a variety of problems by deleting words and replacing them with new words. A much smarter way to do this is to use either the change or the replace commands.

Each command has a lowercase and uppercase version, and each is quite different from the other. The r command replaces the character that the cursor is sitting upon with the next character you type, whereas the R command puts you into replace mode, so that anything you type overwrites whatever is already on the line. By contrast, C replaces everything on the line with whatever you type. The c change command is the most powerful of them all. It works just like the d command. You can use the c command with any address command, and it allows you to change text through that address, whether it's a word, line, or even the rest of the document.

Start vi with the buckaroo.confused file.

I found myself stealing a peek at my own watch and overhead

General Catbird's

I found myself stealing a peek at my own watch and overhead

General Catbird's

aide give him the latest.

"He's not even here," went the conversation.

"Banzai."

"Where the hell is he?"

"At the hospital in El Paso."

"What? Why weren't we informed? What's wrong with him?"

aide give him the latest.

"He's not even here," went the conversation.

"Banzai."

"Where the hell is he?"

"At the hospital in El Paso."

"What? Why weren't we informed? What's wrong with him?"

~

~

~

~

~

~

"buckaroo.confused" 16 lines, 540 characters

Without moving the cursor at all, press R. Nothing happens, or so it seems. Now type the words Excerpt from "Buckaroo Banzai" and watch what happens:

Excerpt from "Buckaroo Banzai"at my own watch and overhead

General Catbird's

I found myself stealing a peek at my own watch and overhead

General Catbird's

aide give him the latest.

"He's not even here," went the conversation.

Now press Esc and notice that what you see on the screen is exactly what's in the file.

This isn't, however, quite what you want. You could use either D or d$ to delete through the end of the line, but that's a bit awkward. Instead, use 0 to move back to the beginning of the line:

Excerpt from "Buckaroo Banzai" at my own watch and overhead

General Catbird's

I found myself stealing a peek at my own watch and overhead

General Catbird's

aide give him the latest.

"He's not even here," went the conversation.

This time, press C to change the contents of the line. Before you even type a single character of the new text, notice what the line now looks like:

Excerpt from "Buckaroo Banzai" at my own watch and overhead

General Catbird'$

I found myself stealing a peek at my own watch and overhead

General Catbird's

aide give him the latest.

"He's not even here," went the conversation.

Here's where a subtle difference comes into play! Look at the very last character on the current line. When you pressed C, the program replaced the "s" with a "$" to show the range of the text to be changed by the command. Press the Tab key once, and then type Excerpt from "Buckaroo Bansai" by Earl MacRauch.

Excerpt from "Buckaroo Bansai" by Earl MacRauchhead General Catbird'$

I found myself stealing a peek at my own watch and overhead

General Catbird's

aide give him the latest.

"He's not even here," went the conversation.

This time, watch what happens when you press Esc:

Excerpt from "Buckaroo Bansai" by Earl MacRauch

I found myself stealing a peek at my own watch and overhead

General Catbird's

aide give him the latest.

"He's not even here," went the conversation.

There's another mistake. It should be Buckaroo Banzai, not Bansai. This is a chance to try the new r command.

Use cursor control keys to move the cursor to the offending letter. Use b to back up words and then h a few times to move into the middle of the word. Your screen now looks like this:

                Excerpt from "Buckaroo Bansai" by Earl MacRauch

I found myself stealing a peek at my own watch and overhead

General Catbird's

aide give him the latest.

"He's not even here," went the conversation.

Now press r. Again, nothing happens; the cursor doesn't move. Press r again to make sure it worked:

Excerpt from "Buckaroo Banrai" by Earl MacRauch

I found myself stealing a peek at my own watch and overhead

General Catbird's

aide give him the latest.

"He's not even here," went the conversation.

That's no good. It replaced the "s" with an "r," which definitely isn't correct. Press rz, and you should have the following:

Excerpt from "Buckaroo Banzai" by Earl MacRauch

I found myself stealing a peek at my own watch and overhead

General Catbird's

aide give him the latest.

"He's not even here," went the conversation.

Okay, those are the easy ones. Now it's time to see what the c command can do for you. In fact, it's incredibly powerful. You can change just about any range of information from the current point in the file in either direction!

To start, move to the middle of the file, where the second copy of the passage is found:

Excerpt from "Buckaroo Banzai" by Earl MacRauch

I found myself stealing a peek at my own watch and overhead

General Catbird's

aide give him the latest.

"He's not even here," went the conversation.

"Banzai."

"Where the hell is he?"

"At the hospital in El Paso."

"What? Why weren't we informed? What's wrong with him?"

aide give him the latest.

"He's not even here," went the conversation.

"Banzai."

"Where the hell is he?"

"At the hospital in El Paso."

"What? Why weren't we informed? What's wrong with him?"

~

~

~

~

~

~

~

"buckaroo.confused" 16 lines, 540 characters

Change the word "aide" that the cursor is sitting on to "The tall beige wall clock opted to." First press c and note that, like many other commands in vi, nothing happens. Now press w to change just the first word. The screen should look like this:

"At the hospital in El Paso."

"What? Why weren't we informed? What's wrong with him?"

aid$ give him the latest.

"He's not even here," went the conversation.

"Banzai."

Again, the program has replaced the last character of the change to a $. Now type The tall beige wall clock opted to. Once you reach the $, the editor stops overwriting characters and starts inserting them instead, so the screen now looks like this:

"At the hospital in El Paso."

"What? Why weren't we informed? What's wrong with him?"

The tall beige wall clock opted to_give him the latest.

"He's not even here," went the conversation.

"Banzai."

Press Esc and you're done (though you can undo the change with the u or U commands, of course).

Tall and beige or not, this section makes no sense now, so change this entire line using the $ motion command. First use 0 to move to the beginning of the line and then press c$:

"At the hospital in El Paso."

"What? Why weren't we informed? What's wrong with him?"

The tall beige wall clock opted to give him the latest$

"He's not even here," went the conversation.

"Banzai."

This is working. The last character changed to the dollar sign. Press Esc, and the entire line is deleted:

"At the hospital in El Paso."

"What? Why weren't we informed? What's wrong with him?"

_

"He's not even here," went the conversation.

"Banzai."

There are still five lines below the current line. You could delete them and then type in the information you want, but that's primitive. Instead, the c command comes to the rescue. Move down one line, press c5, and press Return. Watch what happens:

"At the hospital in El Paso."

"What? Why weren't we informed? What's wrong with him?"

~

~

~

~

~

~

~

~

~

~

~

~

6 lines changed

In general, you can always change the current and next line by using c followed by Return (because the Return key is a motion key too, remember). By prefacing the command with a number, you changed the range from two lines to five.

You might be asking, "Why two lines?" The answer is subtle. In essence, anytime you use the c command you change the current line plus any additional lines that might be touched by the command. Pressing Return moves the cursor to the following line; therefore, the current line (starting at the cursor location) through the following line are changed. The command should probably just change to the beginning of the following line, but that's beyond our control!

Now press Tab four times, type in (page 8), and press the Esc key. The screen should look like this:

"Where the hell is he?"

"At the hospital in El Paso."

"What? Why weren't we informed? What's wrong with him?"

                                (page 8)

~

~

~

What if you change your mind? That's where the u command comes in handy. A single press of the key and the original copy is restored:

Excerpt from "Buckaroo Banzai" by Earl MacRauch

I found myself stealing a peek at my own watch and overhead

General Catbird's

aide give him the latest.

"He's not even here," went the conversation.

"Banzai."

"Where the hell is he?"

"At the hospital in El Paso."

"What? Why weren't we informed? What's wrong with him?"

"He's not even here," went the conversation.

"Banzai."

"Where the hell is he?"

"At the hospital in El Paso."

"What? Why weren't we informed? What's wrong with him?"

~

~

~

~

~

~

~

5 more lines

The combination of replace and change commands adds a level of sophistication to an editor you might have thought could only insert and delete. There's much more to cover, so don't stop now!

Numeric Repeat Prefixes

You have now seen two commands that were prefixed by a number to cause a specific action. The G command moves you to the very last line of the file, unless you type in a number first. If you type in a number, the G command moves to the specified line number. Similarly, pressing a number and then the Return key causes vi to repeat the key the specified number of times.

Numeric repeat prefixes are actually widely available in vi, and this is the missing piece of your navigational tool set.

Move back to the top of the buckaroo.confused file. This time, use 1G to move there, rather than a bunch of k keys or other steps. The top of the screen now looks like this:

Excerpt from "Buckaroo Banzai" by Earl MacRauch

I found myself stealing a peek at my own watch and overhead

General Catbird's

aide give him the latest.

"He's not even here," went the conversation.

Now move forward 15 words. Instead of pressing w 15 times, enter 15w.

Excerpt from "Buckaroo Banzai" by Earl MacRauch

I found myself stealing a peek at my own watch and overhead

General Catbird's

aide give him the latest.

"He's not even here," went the conversation.

Now move down seven lines by pressing the 7 key followed by the Return key. Use o to give yourself a blank line and press Esc again:

"Where the hell is he?"

"At the hospital in El Paso."

"What? Why weren't we informed? What's wrong with him?"

_

"He's not even here," went the conversation.

"Banzai."

You want to put "Go Team Banzai!" on the bottom, repeated three times. Can you guess how to do it? Simply press 3i to move into insert mode, and then type Go Team Banzai!. The screen looks like this:

"Where the hell is he?"

"At the hospital in El Paso."

"What? Why weren't we informed? What's wrong with him?"

Go Team Banzai! _

"He's not even here," went the conversation.

"Banzai."

Pressing Esc has a dramatic result:

"Where the hell is he?"

"At the hospital in El Paso."

"What? Why weren't we informed? What's wrong with him?"

Go Team Banzai! Go Team Banzai! Go Team Banzai!

"He's not even here," went the conversation.

"Banzai."

Now get rid of all the lines below the current line. There are many different ways to do this, but you're going to try to guess how many words are present and give dw a repeat count prefix to delete that many words. (Actually, you don't need to know the number of words, because vi will repeat the command only while it makes sense to do so).

I press 75dw and the screen instantly looks like this:

                Excerpt from "Buckaroo Banzai" by Earl MacRauch

I found myself stealing a peek at my own watch and overhead

General Catbird's

aide give him the latest.

"He's not even here," went the conversation.

"Banzai."

"Where the hell is he?"

"At the hospital in El Paso."

"What? Why weren't we informed? What's wrong with him?"

Go Team Banzai! Go Team Banzai! Go Team Banzai!

~

~

~

~

~

~

~

~

~

~

~

7 lines deleted

Try the undo command here to see what happens!

Almost all commands in vi can work with a numeric repeat prefix, even commands that you might not expect to work, such as the i insert command. Remember that a request can be accomplished in many ways. To delete five words, for example, you could use 5dw or d5w. Experiment on your own, and you'll get the idea.

Numbering Lines in the File

It's very helpful to have an editor that works with the entire screen, but sometimes you only need to know what line you're currently on. Further, sometimes it can be very helpful to have all the lines numbered on the screen. With vi, you can do both of these—the former by pressing ^g (remember, that's Ctrl+G) while in command mode, and the latter by using a complex colon command, :set number, followed by Return. To turn off the display of line numbers, simply type :set nonumber and press Return.

You're still looking at buckaroo.confused in vi. The screen looks like this:

Excerpt from "Buckaroo Banzai" by Earl MacRauch

I found myself stealing a peek at my own watch and overhead

General Catbird's

aide give him the latest.

"He's not even here," went the conversation.

"Banzai."

"Where the hell is he?"

"At the hospital in El Paso."

"What? Why weren't we informed? What's wrong with him?"

Go Team Banzai! Go Team Banzai! Go Team Banzai!

~

~

~

~

~

~

~

~

~

~

~

7 lines deleted

Can you see where the cursor is? To find out what line number the cursor is on, press ^g. The information is listed on the status line at the bottom:

~

~

~

"buckaroo.confused" [Modified] line 10 of 11, column 1  —90%—

There's lots of information here. Included here is the name of the file (buckaroo.confused), an indication that vi thinks you've changed it since you started the program ([Modified]), the current line (10), total lines in the file (11), what column you're in, and, finally, an estimate of how far into the file you are.

Eleven lines? Count the display again. There are 12 lines. What's going on? The answer will become clear if you turn on line numbering for the entire file. To do this, type :, which zips the cursor to the bottom of the screen, where you then enter the set number command:

~

~

~

:set number_

Pressing Return causes the screen to change, thus:

1          Excerpt from "Buckaroo Banzai" by Earl MacRauch

     2  I found myself stealing a peek at my own watch and overhead General Catbird's

     3  aide give him the latest.

     4  "He's not even here," went the conversation.

     5  "Banzai."

     6  "Where the hell is he?"

     7  "At the hospital in El Paso."

     8  "What? Why weren't we informed? What's wrong with him?"

     9

    10  Go Team Banzai! Go Team Banzai! Go Team Banzai!

    11

~

~

~

~

~

~

~

~

~

~

Now you can see why vi only figures that there are 11 lines, even though it seems by the screens shown here that there are 12 lines.

To turn off the line numbering, use the opposite command, :set nonumber, followed by Return.

There are definitely times when being able to include the number of each line is helpful. One example is if you are using awk and it's complaining about a specific line being in an inappropriate format (usually by saying syntax error, bailing out! or something similar).

Search and Replace

Though most of vi is easy to learn and use, one command that always causes great trouble for users is the search and replace command. The key to understanding this command is to remember that there's a line editor (ex) hidden underneath vi. Instead of trying to figure out some arcane vi command, it's easiest to just drop to the line editor and use a simple colon command—one identical to the command used in sed—to replace an old pattern with a new one. To replace an existing word on the current line with a new word (the simplest case), use :s/old/new/. If you want to have all occurrences on the current line matched, you need to add the g suffix (just as with sed): :s/old/new/g.

To change all occurrences of one word or phrase to another across the entire file, the command is identical to the preceding command, except that you must add a prefix indicating the range of lines affected. Recall that $ is the last line in the file, and that ranges are specified (in this case, as in sed) by two numbers separated by a comma. It should be no surprise that the command is :1,$ s/old/new/g.

You're still working with the buckaroo.confused file, so your screen should look very similar to this:

Excerpt from "Buckaroo Banzai" by Earl MacRauch

I found myself stealing a peek at my own watch and overhead

General Catbird's

aide give him the latest.

"He's not even here," went the conversation.

"Banzai."

"Where the hell is he?"

"At the hospital in El Paso."

"What? Why weren't we informed? What's wrong with him?"

Go Team Banzai! Go Team Banzai! Go Team Banzai!

~

~

~

~

~

~

~

~

~

~

~

~

~

~

The cursor is on the very first line. Rename Earl. Type :. The cursor immediately moves to the bottom. Then type s/Earl/Duke/. Pressing Return produces this:

Excerpt from "Buckaroo Banzai" by Duke MacRauch

I found myself stealing a peek at my own watch and overhead General Catbird's

aide give him the latest.

"He's not even here," went the conversation.

As you can see, this maneuver was simple and effective.

Maybe developmental psychology is your bag. Instead of having this Banzai character, you want your fictional character to be called Bandura. You could use the previous command to change the occurrence on the current line, but you really want to change all occurrences within the file.

This is no problem. Type :1,$ s/Banzai/Bandura/ and press Return. Here's the result:

Excerpt from "Buckaroo Bandura" by Duke MacRauch

I found myself stealing a peek at my own watch and overhead

General Catbird's

aide give him the latest.

"He's not even here," went the conversation.

"Bandura."

"Where the hell is he?"

"At the hospital in El Paso."

"What? Why weren't we informed? What's wrong with him?"

Go Team Bandura! Go Team Banzai! Go Team Banzai!

~

~

~

~

~

~

~

~

~

~

~

~

~

The result is not quite right. You forgot the trailing g, so vi changed only the very first occurrence on each line, making the "go team" exhortation rather confusing.

To try again, type :1,$ s/Banzai/Bandura/g and press Return. The screen changes as desired:

Excerpt from "Buckaroo Bandura" by Duke MacRauch

I found myself stealing a peek at my own watch and overhead

General Catbird's

aide give him the latest.

"He's not even here," went the conversation.

"Bandura."

"Where the hell is he?"

"At the hospital in El Paso."

"What? Why weren't we informed? What's wrong with him?"

Go Team Bandura! Go Team Bandura! Go Team Bandura!

~

~

~

~

~

~

~

~

~

~

~

7 substitutions

Notice that vi also indicates the total number of substitutions in this case.

Press u to undo the last change.

Search and replace is one area where a windowing system, like that on a Macintosh or a PC running Windows, comes in handy. A windowing system offers different boxes for the old and new patterns, and shows each change and a dialog box asking, "Should I change this one?" Alas, this is UNIX and it's still designed to run on ASCII terminals.

Key Mapping with the map Command

As you have worked through the various examples, you might have tried pressing the arrow keys on your keyboard or perhaps the Ins or Del keys. Odds are likely that the keys not only didn't work, but instead caused all sorts of weird things to happen!

The good news is that vi has a facility that enables you to map any key to a specific action. If these key mappings are saved in a file called .exrc in your home directory, the mappings will be understood by vi automatically each time you use the program. The format for using the map command is :map key command-sequence. (In a nutshell, mapping is a way of associating an action with another action or result. For example, by plugging your computer into the right wall socket, you could map the action of flipping the light switch on the wall with the result of having your computer turn on.)

You can also save other things in your .exrc file, including the :set number option if you're a nut about seeing line numbers. More interestingly, vi can be taught abbreviations, so that each time you press the abbreviation, vi expands it. The format for defining abbreviations is :abbreviate abbreviation expanded-value. Finally, any line that begins with a double quote is considered a comment and is ignored.

It's finally time to leave the buckaroo.confused file, and restart vi, this time with the .exrc file in your home directory:

% cd 

% vi .exrc

_

~

~

~

~

~

~

~

~

~

~

~

~

~

~

~

~

~

~

~

~

~

~

".exrc" [New file]

Before you actually add any information to this new file, define a few abbreviations to make life a bit easier. To do this, press :, which moves the cursor to the bottom of the screen. Then define tyu as a simple abbreviation for the lengthy phrase Teach Yourself UNIX in a Few Minutes:

~

~

~

:abbreviate tyu Teach Yourself UNIX in a Few Minutes_

Pressing Return moves the cursor back to the top.

Now try the abbreviation. Recall that in the .exrc, lines beginning with a double quote are comments and are ignored when vi starts up. Press i to enter insert mode, and then type " Sample .exrc file as shown in tyu. The screen looks like this:

" Sample .exrc file as shown in tyu_

~

~

As soon as you press Return or enter a space or punctuation character, the abbreviation is expanded. In this case, move to the next line by pressing Return:

" Sample .exrc file as shown in Teach Yourself UNIX in a Few Minutes

_

~

~

Press Esc to leave the insert mode.

This feature can also be used to correct common typos you make. Many people have a bad habit of typing "teh" instead of "the." Because vi is smart about abbreviation expansion, you can abbreviate "the" as "teh" and not get into trouble:

~

~

:ab teh the_

TIP: You don't have to type "abbreviation" each time. The first two letters are sufficient for vi to figure out what's going on.

Press Return. Now whenever you make that typo, the editor will fix it. To demonstrate this, add a second comment to this file. Adding a comment is easy because you're still at the beginning of the second line. When you press i and type " (subtly different from the example in teh, you get the following result:

" Sample .exrc file as shown in Teach Yourself UNIX in a Few Minutes

" (subtly different from the example in the_

~

~

If you enter another character instead of pressing the spacebar, vi is smart enough not to expand the abbreviation. Try it yourself. After pressing the h key again, you'll see this:

" Sample .exrc file as shown in Teach Yourself UNIX in a Few Minutes

"  (subtly different from the example in tehh_

~

~

Because you're still in insert mode, however, you can backspace and replace the spare h with a space, which instantly fixes the spelling. Finally, type book) and press Esc to return to command mode.

There's one more nifty abbreviation trick. Type :ab by itself and press Return. vi shows you a list of the abbreviations currently in effect:

~

~

:ab

tyu     tyu     Teach Yourself UNIX in a Few Minutes

teh     teh     the

 [Hit any key to continue]  _

Okay, now you can move on to key mapping.

Key mapping is as easy as defining abbreviations, except you must remember one thing: any control character entered must be prefaced with a ^v so that vi doesn't interpret it immediately. The Esc key is included in this list, too.

To map the Clear key to the D function, which, as you recall, deletes text through the end of the current line, type :map, followed by a single space:

~

~

:map

WARNING: If you use many different terminals, you may have to remap the Clear (Clr) key.

Now you need to type the ^v; otherwise, when you press the Clear key, it will send an Escape sequence that will confuse vi to no end. Press ^v:

~

~

:map ^

The cursor is floating over the caret, which indicates the next character typed should be a control character. Instead of pressing any specific character, however, simply press the Clear key. The result is that it sends the Escape sequence, and vi captures it without a problem:

~

~

:map ^[OP_

Now type another space, because the key part of the key mapping has been defined. Then type the command to which vi should map the Clear key:

~

~

:map ^[OP D_

Press Return, and it's done! To test the key mapping, move back to the phrase Few Minutes in the first line:

" Sample .exrc file as shown in Teach Yourself UNIX in a Few Minutes

"  (subtly different from the example in the book)

~

~

To clear this line, you need only press Clear.

To save this as a permanent key mapping in this .exrc file, duplicate each keystroke, but this time do it in insert mode instead of at the bottom of the screen. The result is a file that looks like this:

" Sample .exrc file as shown in Teach Yourself UNIX in a

"  (subtly different from the example in the book)

:map ^[OP D_

~

~

Mapping the arrow keys is done the same way, and typing :ab and then pressing Return shows all abbreviations. Typing :map and then Return demonstrates that you already have your arrow keys mapped to the vi motion keys:

~

~

:map

up      ^[[A    k

down    ^[[B    j

left    ^[[D    h

right   ^[[C    l

^[OP    ^[OP    D

 [Hit any key to continue] _

You can see that sometimes the system can be smart about defining specific keys by name rather than by value, but the end result is the same. You can now use the arrow keys and Clear key, and vi knows what they mean.

Here's a final demonstration of what you can do with keyboard mapping. You'll often encounter a simple, tedious activity you must do over and over. An example might be surrounding a specific word with quotes to meet a style guideline. This sounds more painful than it need be, because a simple key mapping can automate the entire process of quoting the current word.

You know that ^a isn't used by vi, so you can map that to the new quote-a-single-word command, making sure that you use ^v before each control character or Esc. Type the characters :map ^v^a i":

~

~

:map ^A i"_

Press ^v and then the Esc key. To insert a double quote, you need to have vi go into insert mode (the i), type the quote, and receive an Esc to leave insert mode. The e command moves to the end of the current word, so type that, followed by the commands needed to append the second double quote. The final map now looks like this:

~

~

:map ^A i"^[ea"^[_

Press Return and it's done. Now move to the beginning of a word and try the new key mapping for ^a.

There are a variety of customizations you can use with the vi editor, including teaching it about special keys on your keyboard and defining task-specific keys to save time. You can use it to abbreviate commonly used words or phrases to save time or avoid typographical errors. Be cautious when working with the .exrc file, however, because if you enter information that isn't valid, it can be a bit confusing to fix it. Always try the command directly before using it in a special key mapping, and you'll stay out of trouble.

Moving Sentences and Paragraphs

You've learned quite a variety of different commands for moving about in files, but there are two more vi movement commands for you to try. So far, movement has been based on screen motion, but vi hasn't particularly known much about the information in the file itself: press k and you move up a line, regardless of what kind of file you're viewing.

The vi editor is smarter than that, however. It has some movement commands that are defined by the text you're currently editing. Each of these is simply a punctuation character on your keyboard, but each is quite helpful. The first is ), which moves the cursor forward to the beginning of the next sentence in the file. Use the opposite, (, and you can move to the beginning of the current sentence in the file. Also worth experimenting with is }, which moves forward a paragraph in the file, and {, which moves backwards a paragraph.

To try this out, create a new file. Start vi and type the following text:

% cat dickens.note

                                A Tale of Two Cities

                                      Preface

When I was acting, with my children and friends, in Mr Wilkie Collins's

drama of The Frozen Deep, I first conceived the main idea of this

story.  A strong desire was upon me then, to

embody it in my own person;

and I traced out in my fancy, the state of mind of which it would

necessitate the presentation

to an observant spectator, with particular

care and interest.

As the idea became familiar to me, it gradually shaped itself into its

present form.  Throughout its execution, it has had complete possession

of me; I have so far verified what

is done and suffered in these pages,

as that I have certainly done and suffered it all myself.

Whenever any reference (however slight) is made here to the condition

of the French people before or during the Revolution, it is truly made,

on the faith of the most trustworthy

witnesses.  It has been one of my hopes to add

something to the popular and picturesque means of

understanding that terrible time, though no one can hope

to add anything to the philosophy of Mr Carlyle's wonderful book.

Tavistock House

November 1859

When you start vi on this file, here's what your initial screen looks like:

A Tale of Two Cities

                                      Preface

When I was acting, with my children and friends, in Mr Wilkie Collins's

drama of The Frozen Deep, I first conceived the main idea of this

story.  A strong desire was upon me then, to

embody it in my own person;

and I traced out in my fancy, the state of mind of which it would

necessitate the presentation

to an observant spectator, with particular

care and interest.

As the idea became familiar to me, it gradually shaped itself into its

present form.  Throughout its execution, it has had complete possession

of me; I have so far verified what

is done and suffered in these pages,

as that I have certainly done and suffered it all myself.

Whenever any reference (however slight) is made here to the condition

of the French people before or during the Revolution, it is truly made,

on the faith of the most trustworthy

witnesses.  It has been one of my hopes to add

something to the popular and picturesque means of

"dickens.note" 28 lines, 1122 characters

Move to the beginning of the first paragraph of text by typing /When and pressing Return. Now the screen looks like this:

A Tale of Two Cities

                                      Preface

When I was acting, with my children and friends, in Mr Wilkie Collins's

drama of The Frozen Deep, I first conceived the main idea of this

story.  A strong desire was upon me then, to

embody it in my own person;

Press ) once. The cursor moves to the beginning of the next sentence:

When I was acting, with my children and friends, in Mr Wilkie Collins's

drama of The Frozen Deep, I first conceived the main idea of this

story.  A strong desire was upon me then, to

embody it in my own person;

and I traced out in my fancy, the state of mind of which it would

necessitate the presentation

Try the ( to move back a sentence. You end up back on the "W" in "When" at the beginning of the sentence. Repeatedly pressing ( and ) should let you fly back and forth through the file, sentence by sentence. Notice what occurs when you're at the top few lines of the title.


WARNING: A little experimentation will demonstrate that vi defines a sentence as anything that occurs at the beginning of a block of text (for example, When I was_), or as any word that follows a punctuation character followed by two spaces. This is a bit unfortunate, because modern typographic conventions have moved away from using two spaces after the end of a sentence. If you only use one space between sentences—as I have for this book—moving by sentence is less helpful.

You can move back to the opening word of the first paragraph by pressing n to repeat the last search pattern. The screen now looks like this:

A Tale of Two Cities

                                      Preface

When I was acting, with my children and friends, in Mr Wilkie Collins's

drama of The Frozen Deep, I first conceived the main idea of this

story.  A strong desire was upon me then, to

embody it in my own person;

and I traced out in my fancy, the state of mind of which it would

necessitate the presentation

to an observant spectator, with particular

care and interest.

As the idea became familiar to me, it gradually shaped itself into its

present form.  Throughout its execution, it has had complete possession

of me; I have so far verified what

is done and suffered in these pages,

as that I have certainly done and suffered it all myself.

Whenever any reference (however slight) is made here to the condition

of the French people before or during the Revolution, it is truly made,

on the faith of the most trustworthy

witnesses.  It has been one of my hopes to add

something to the popular and picturesque means of

"dickens.note" 28 lines, 1122 characters

To move to the next paragraph, press } once:

A Tale of Two Cities

                                      Preface

When I was acting, with my children and friends, in Mr Wilkie Collins's

drama of The Frozen Deep, I first conceived the main idea of this

story.  A strong desire was upon me then, to

embody it in my own person;

and I traced out in my fancy, the state of mind of which it would

necessitate the presentation

to an observant spectator, with particular

care and interest.

As the idea became familiar to me, it gradually shaped itself into its

present form.  Throughout its execution, it has had complete possession

of me; I have so far verified what

is done and suffered in these pages,

as that I have certainly done and suffered it all myself.

Whenever any reference (however slight) is made here to the condition

of the French people before or during the Revolution, it is truly made,

on the faith of the most trustworthy

witnesses.  It has been one of my hopes to add

something to the popular and picturesque means of

"dickens.note" 28 lines, 1122 characters

Press the { key and you move right back to the beginning of the previous paragraph. In fact, you can easily fly back and forth in the file by using sequences of } (or a numeric repeat prefix like 2} to get there faster).

These two motion commands are helpful when you're working with stories, articles, or letters. Anytime you're working with words rather than commands (as in the .exrc file), these commands are worth remembering.

By the way, try d) to delete a sentence, or c} to change an entire paragraph. Remember that you can always undo the changes with u if you haven't done anything else between the two events.

Access UNIX with !

This final section on vi introduces you to one of the most powerful, and least known, commands in the editor: the ! Escape-to-UNIX command. When prefaced with a colon (:!, for example), it enables you to run UNIX commands without leaving the editor. More importantly, the ! command itself, just like d and c, accepts address specifications and feeds that portion of text to the command, and then replaces that portion with the results of having run that command on the text.

You should still be in the dickens.intro file. Start by double-checking what files you have in your home directory. To do this, type :!, which moves the cursor to the bottom line:

of the French people before or during the Revolution, it is truly made,

on the faith of the most trustworthy

witnesses.  It has been one of my hopes to add

something to the popular and picturesque means of

:!_

Type ls -CF and press Return, as if you were at the % prompt in the command line:

of the French people before or during the Revolution, it is truly made,

on the faith of the most trustworthy

witnesses.  It has been one of my hopes to add

something to the popular and picturesque means of

:!ls -CF

Archives/          big.output         dickens.note       src/

InfoWorld/         bigfiles           keylime.pie        temp/

Mail/              bin/               newfile            tetme

News/              buckaroo           owl.c

OWL/               buckaroo.confused  sample

awkscript          demo               sample2

 [Hit any key to continue] _

Press Return and you're back in the editor. You have quickly checked what files you have in your home directory. (Your fileage may vary.)

Now for some real fun. Move back to the beginning of the first paragraph and add the text "Chuck, here are my current files:" to it. Press Return twice before using the Esc key to return to command mode:

A Tale of Two Cities

                                      Preface

Chuck, here are my current files:

_

When I was acting, with my children and friends, in Mr Wilkie Collins's

drama of The Frozen Deep, I first conceived the main idea of this

story.  A strong desire was upon me then, to

Notice that the cursor was moved up a line. You're now on a blank line, and the line following is also blank.

To feed the current line to the UNIX system and replace it with the output of the command, vi offers an easy shortcut: !!. As soon as you type the second ! (or, more precisely, once vi figures out the desired range specified for this command), the cursor moves to the bottom of the screen and prompts with a single ! character:

of the French people before or during the Revolution, it is truly made,

on the faith of the most trustworthy

witnesses. It has been one of my hopes to add

something to the popular and picturesque means of

!_

To list all the files in your directory, again type ls -CF and press Return. After a second, vi adds the output of that command to the file:

A Tale of Two Cities

                                      Preface

Chuck, here are my current files:

Archives/               bigfiles                newfile

InfoWorld/              bin/                    owl.c

Mail/                   buckaroo                sample

News/                   buckaroo.confused       sample2

OWL/                    demo                    src/

awkscript               dickens.note            temp/

big.output              keylime.pie             tetme

When I was acting, with my children and friends, in Mr Wilkie Collins's

drama of The Frozen Deep, I first conceived the main idea of this

story.  A strong desire was upon me then, to

embody it in my own person;

and I traced out in my fancy, the state of mind of which it would

necessitate the presentation

to an observant spectator, with particular

care and interest.

As the idea became familiar to me, it gradually shaped itself into its

present form.  Throughout its execution, it has had complete possession

6 more lines

Notice that this time that the status on the bottom indicates how many lines were added to the file.

Press u to undo this change. Notice that the vi status indicator on the bottom line says there are now six fewer lines.

Move back to the "W" in "When." You are now ready to learn one of the most useful commands in vi. This command gives you the ability to hand a paragraph of text to an arbitrary UNIX command.

This time, use a sed command, sed 's/^/> /', which prefaces each line with >. Ready? This is where the } command comes in handy, too. To accomplish this trick, type !}, moving the cursor to the bottom of the screen. Then type the sed command as you saw earlier: sed 's/^/> /'. Pressing Return feeds the lines to sed. The sed command makes the change indicated and replaces those lines with the output of the sed command. Voilà! The screen now looks like this:

A Tale of Two Cities

                                      Preface

Chuck, here are my current files:

> When I was acting, with my children and friends, in Mr Wilkie Collins's

> drama of The Frozen Deep, I first conceived the main idea of this

> story.  A strong desire was upon me then, to

> embody it in my own person;

> and I traced out in my fancy, the state of mind of which it would

> necessitate the presentation

> to an observant spectator, with particular

> care and interest.

As the idea became familiar to me, it gradually shaped itself into its

present form.  Throughout its execution, it has had complete possession

of me; I have so far verified what

is done and suffered in these pages,

as that I have certainly done and suffered it all myself.

Whenever any reference (however slight) is made here to the condition

of the French people before or during the Revolution, it is truly made,

!sed 's/^/> /'

Here are a few more examples of ways to interact with UNIX while within vi. First, you don't really want the prefix to each line, so choose u to undo the change.

You want the system to actually tighten up the lines, ensuring that a reasonable number of words occur on each line without any lines being too long. On the majority of systems, there is a command called either fmt or adjust to accomplish this. To figure out which works on your system, simply use the :! command and feed a word or two to the fmt command to see what happens:

Whenever any reference (however slight) is made here to the condition

of the French people before or during the Revolution, it is truly made,

:!echo hi | fmt

[No write since last change]

hi

 [Hit any key to continue] _

In this case, fmt worked as expected, so you can be sure that the command exists on your system. If the response was command unknown, adjust is a likely synonym. If neither exist, complain to your vendor!

Armed with this new command, you can try another variant of !}, this time by feeding the entire paragraph to the fmt command. You're still at the beginning of the word "When" in the text. When you type the command !}fmt, the paragraph is cleaned up, and the screen changes to this:

A Tale of Two Cities

                                      Preface

Chuck, here are my current files:

When I was acting, with my children and friends, in Mr Wilkie Collins's

drama of The Frozen Deep, I first conceived the main idea of this

story.  A strong desire was upon me then, to embody it in my own

person; and I traced out in my fancy, the state of mind of which it

would necessitate the presentation to an observant spectator, with

particular care and interest.

As the idea became familiar to me, it gradually shaped itself into its

present form.  Throughout its execution, it has had complete possession

of me; I have so far verified what

is done and suffered in these pages,

as that I have certainly done and suffered it all myself.

Whenever any reference (however slight) is made here to the condition

of the French people before or during the Revolution, it is truly made,

on the faith of the most trustworthy

witnesses.  It has been one of my hopes to add

2 fewer lines

Again, vi tells you that the number of lines in the file have changed as a result of the command. In this situation, tightening up the paragraph actually reduced it by two display lines, too.

This command is so helpful that you may want to have it bound to a specific key with the keymap command. A typical way to do this in an .exrc might be this:

:map ^P !}fmt^M

The ^M is what vi uses to record an Return keypress. (Remember that you need to use ^v beforehand.) With this defined in your .exrc, you can press ^p to format the current paragraph.

The awk command, discussed in Chapter 15, "Awk, Awk," can easily be used to extract specific fields of information. This can be tremendously helpful in vi. Rather than continuing with the dickens.intro file, however, quit vi and create a new file containing some output from the ls command:

% ls -CF

Archives/          big.output         dickens.note       src/

InfoWorld/         bigfiles           keylime.pie        temp/

Mail/              bin/               newfile            tetme

News/              buckaroo           owl.c

OWL/               buckaroo.confused  sample

awkscript          demo               sample2

% ls -l a* b* > listing

Now you can use vi listing to start the file with the output of the ls command:

-rw-rw——  1 taylor        126 Dec  3 16:34 awkscript

-rw-rw——  1 taylor       1659 Dec  3 23:26 big.output

-rw-rw——  1 taylor        165 Dec  3 16:42 bigfiles

-rw-rw——  1 taylor        270 Dec  4 15:09 buckaroo

-rw-rw——  1 taylor        458 Dec  4 23:22 buckaroo.confused

~

~

~

~

~

~

~

~

~

~

~

~

~

~

~

~

~

~

"listing" 5 lines, 282 characters

It would be nice to use this as the basis for creating a shell script, which is just a series of commands that you might type to the shell directly, all kept neatly in a single file. A shell script can show you both the first and last few lines of each file, with the middle chopped out.

The commands you want to have occur for each file entry are these:

echo ==== filename ====

head -5 filename; echo ...size bytes...; tail -5 filename

Do this with a combination of the ! command in vi and the awk program with the awk command:

awk '{ print "echo ==== "$8" ===="; print "head "$8"; echo

..."$4" bytes...; tail "$8}'

With the cursor on the very top line of this file, you can now press !G to pipe the entire file through the command. The cursor drops to the bottom of the screen. Type in the awk script shown previously and press Return. The result is this:

echo ==== awkscript ====

head -5 awkscript; echo ...126 bytes...; tail -5 awkscript

echo ==== big.output ====

head -5 big.output; echo ...1659 bytes...; tail -5 big.output

echo ==== bigfiles ====

head -5 bigfiles; echo ...165 bytes...; tail -5 bigfiles

echo ==== buckaroo ====

head -5 buckaroo; echo ...270 bytes...; tail -5 buckaroo

echo ==== buckaroo.confused ====

head -5 buckaroo.confused; echo ...458 bytes...; tail -5 buckaroo.confused~

~

~

~

~

~

~

~

~

~

~

~

~

!awk '{ print "echo ==== "$8" ===="; print "head "$8"; echo

..."$4" bytes...; tail "$8}'

If you now quit vi and ask sh to interpret the contents, here's what happens:

% chmod +x listing

% sh listing

==== awkscript ====

{

        count[length($1)]++

}

END {

        for (i=1; i < 9; i++)

...126 bytes...

}

END {

        for (i=1; i < 9; i++)

          print "There are " counti " accounts with " i " letter names."

}

==== big.output ====

leungtc  ttyrV   Dec  1 18:27   (magenta)

tuyinhwa ttyrX   Dec  3 22:38   (expert)

hollenst ttyrZ   Dec  3 22:14   (dov)

brandt   ttyrb   Nov 28 23:03   (age)

holmes   ttyrj   Dec  3 21:59   (age)

...1659 bytes...

buckeye  ttyss   Dec  3 23:20   (mac2)

mtaylor  ttyst   Dec  3 23:22   (dov)

look     ttysu   Dec  3 23:12   (age)

janitor  ttysw   Dec  3 18:29   (age)

ajones   ttysx   Dec  3 23:23   (rassilon)

==== bigfiles ====

12556   keylime.pie

8729    owl.c

1024    Mail/

582     tetme

512     temp/

...165 bytes...

512     Archives/

207     sample2

199     sample

126     awkscript

==== buckaroo ====

I found myself stealing a peek at my own watch and overhead

General Catbird's

aide give him the latest.

"He's not even here," went the conversation.

"Banzai."

"Where the hell is he?"

...270 bytes...

"Banzai."

"Where the hell is he?"

"At the hospital in El Paso."

"What? Why weren't we informed? What's wrong with him?"

==== buckaroo.confused ====

        Excerpt from "Buckaroo Bandura" by Duke MacRauch

I found myself stealing a peek at my own watch and overhead

General Catbird's

aide give him the latest.

"He's not even here," went the conversation.

"Bandura."

...458 bytes...

"At the hospital in El Paso."

"What? Why weren't we informed? What's wrong with him?"

Go Team Bandura! Go Team Bandura! Go Team Bandura!

%

Clearly the ! command opens up vi to work with the rest of the UNIX system. There's almost nothing that you can't do within the editor, whether it's add or remove prefixes, clean up text, or even show what happens when you try to run a command or reformat a passage within the current file. Remember, you can run spell without leaving vi, too. Be careful, though, because spell will replace the entire contents of your file with the list of words it doesn't know. Fortunately, u can solve that problem.

A summary of the commands you have learned in this section is shown in Table 7.3.

Command


Meaning


!!

Replace current line with output of UNIX command.

!}

Replace current paragraph with the results of piping it through the specified UNIX program or programs.

(

Move backward one sentence.

)

Move forward one sentence.

C

Change text through the end of line.

c

Change text in the specified range—cw changes the following word, whereas c} changes the next paragraph.

e

Move to the end of the current word.

^g

Show current line number and other information about the file.

R

Replace text until Esc.

r

Replace the current character with the next pressed.

^v

Prevent vi from interpreting the next character.

{

Move backward one paragraph.

}

Move forward one paragraph.

:!

Invoke specified UNIX command.

:ab a bcd

Define abbreviation a for phrase bcd.

:ab

Show current abbreviations, if any.

:map a bcd

Map key a to the vi commands bcd.

:map

Show current key mappings, if any.

:s/old/new/

Substitute new for old on the current line.

:s/old/new/g

Substitute new for all occurrences of old on the current line.

:1,$s/old/new/g

Substitute new for all occurrences of old.

:set nonumber

Turn off line numbering.

:set number

Turn on line numbering.

Clearly, vi is a very complex and sophisticated tool, allowing you to not only modify your text files but also customize the editor for your keyboard. Just as important, you can access all the power of UNIX while within vi.

With this section and the last, you now know more about vi than the vast majority of people using UNIX today. There's a second popular editor, however; one that is modeless and that offers its own interesting possibilities for working with files and the UNIX system. It's called EMACS, and if you have it on your system, it's definitely worth a look.

The EMACS Editor

The only screen-oriented editor that's guaranteed to be included with the UNIX system is vi, but that doesn't mean that it's the only good editor available. An alternative editor that has become quite popular in the last decade (remember that UNIX is almost twenty-five years old) is called EMACS. This section teaches you the fundamentals of this powerful editing environment.

Remember that EMACS is modeless, so be prepared for an editor that is quite unlike vi. Because it's modeless, there's no insert or command mode. The result is that you have ample opportunity to use the Ctrl key.


NOTE: Over the years, I have tried to become an EMACS enthusiast, once even forcing myself to use it for an entire month. I had crib sheets of commands taped up all over my office. At the end of the month, I was able to edit almost half as fast as I could in vi, which I've used thousands of times in the past fourteen years that I've worked in UNIX. I think EMACS has a lot going for it, and generally I think that modeless software is better than modal software. The main obstacle I see for EMACS is that it's begging for pull-down menus like those in a Mac or Windows program. Using Ctrl, Meta, Shift+Meta, and other weird key combinations just isn't as easy for me. On the other hand, your approach to editing may be different, and you may not have years of vi experience affecting your choice of editing environments. I encourage you to give EMACS a fair shake by working through all the examples I have included. You may find it matches your working style better than vi.

Launching EMACS and Inserting Text

Starting EMACS is as simple as starting any other UNIX program. Simply type the name of the program, followed by any file or files you'd like to work with. The puzzle with EMACS is figuring out what it's actually called on your system, if you even have it.

Once in EMACS, it's important to take a look at your computer keyboard. EMACS requires you to use not just the Ctrl key, but another key known as the Meta key, a sort of alternative Ctrl key. If you have a key labelled Meta or Alt on your keyboard, that's the one. If, like me, you don't, press Esc every time a Meta key is indicated.

Because there are both Ctrl and Meta keys in EMACS, the notation for indicating commands is slightly different. Throughout this chapter, a control key sequence has been shown either as Ctrl+F or ^f. EMACS people write this differently to allow for the difference between the Ctrl and Meta keys. In EMACS notation, ^f is shown as C-f, where C- always means Ctrl. Similarly, M-x is the Meta key plus x. If you don't have a Meta key, the sequence is Esc, followed by x. Finally, some arcane commands involve both the Ctrl and Meta keys being pressed simultaneously with the other key involved. The notation is C-M-x. This indicates that you need to either press and hold down both the Ctrl and Meta keys while pressing x, or, if you don't have a Meta (or Alt) key, press Esc followed by C-x.

With this notation in mind, leave EMACS by pressing C-x C-c (Ctrl+X, followed by Ctrl+C).

First, see if your system has EMACS available. The easiest way to find out is to type emacs at the command line and see what happens.

% emacs

emacs: Command not found.

%

This is a good indication that EMACS isn't available. If your command worked and you now are in the EMACS editor, move down to step 2.

A popular version of EMACS, called GNU EMACS, comes from the Free Software Foundation. To see if you have this version, type gnuemacs or gnumacs at the command line.

If this fails to work, you can try one more command before you accept that EMACS isn't part of your installation of UNIX. Online documentation for UNIX is accessible through the man command. The actual database of documents also includes a primitive but helpful keyword search capability, accessible by specifying the -k option (for keyword searches) at the command line. To find out if you have EMACS, enter the following:

% man -k emacs

gnuemacs (1l)   - GNU project Emacs

%

This indicates that GNU EMACS is on the system and can be started by entering gnuemacs at the command line.

Rather than start with a blank screen, quit the program (C-x C-c) and restart EMACS with one of the earlier test files, dickens.note:

% gnuemacs dickens.note

_                              A Tale of Two Cities

                                      Preface

When I was acting, with my children and friends, in Mr Wilkie Collins's

drama of The Frozen Deep, I first conceived the main idea of this

story. A strong desire was upon me then, to

embody it in my own person;

and I traced out in my fancy, the state of mind of which it would

necessitate the presentation

to an observant spectator, with particular

care and interest.

As the idea became familiar to me, it gradually shaped itself into its

present form. Throughout its execution, it has had complete possession

of me; I have so far verified what

is done and suffered in these pages,

as that I have certainly done and suffered it all myself.

Whenever any reference (however slight) is made here to the condition

of the French people before or during the Revolution, it is truly made,

on the faith of the most trustworthy

witnesses. It has been one of my hopes to add

——Emacs: dickens.note           (Fundamental)——Top—————————-

As you can see, it's quite different from the display shown when vi starts up. The status line at the bottom of the display offers useful information as you edit the file at different points. It also displays the name of the file at all times, a feature that can be surprisingly helpful. EMACS can work with different kinds of files. Here you see by the word "Fundamental" in the status line that EMACS is prepared for a regular text file. If you're programming, EMACS can offer special features customized for your particular language.

Quit EMACS by using the C-x C-c sequence, but let a few seconds pass after you press C-x to see what happens. When you press C-x, the bottom of the screen suddenly changes to this:

on the faith of the most trustworthy

witnesses. It has been one of my hopes to add

——Emacs: dickens.note           (Fundamental)——Top————————————

C-x-

Confusingly, the cursor remains at the top of the file, but EMACS reminds you that you've pressed C-x and that you need to enter a second command once you've decided what to do. Press C-c and immediately exit EMACS.

Already you can see there are some dramatic differences between EMACS and vi. If you're comfortable with multiple key sequences like C-x C-c to quit, you're going to enjoy learning EMACS. If not, stick with it anyway. Even if you never use EMACS, it's good to know a little bit about it.

How to Move Around in a File

Files are composed of characters, words, lines, sentences, and paragraphs, and EMACS has commands to help you move around in them. Most systems have the arrow keys enabled, which means you won't need some of the key sequences, but it's best to know them all anyway.

The most basic motions are C-f and C-b, which are used to move the cursor forward and backward one character, respectively. Switch those to the Meta command equivalents and the cursor will move word by word: M-f moves the cursor forward a word and M-b moves it back a word. Pressing C-n moves the cursor to the next line, C-p moves it to the previous line, C-a moves it to the beginning of the line, and C-e moves it to the end of the line. (The vi equivalents for these are l, h, w, and b for moving forward and backward a character or word; j and k for moving up or down a line; and 0 or $ to move to the beginning or end of the current line. Which makes more sense to you?)

To move forward a sentence you can use M-e, which actually moves the cursor to the end of the sentence. Pressing M-a moves it to the beginning of the sentence. Notice the parallels between Ctrl and Meta commands: C-a moves the cursor to the beginning of the line, and M-a moves it to the beginning of the sentence.

Scrolling within the document is accomplished by using C-v to move forward a screen and M-v to move back a screen. To move forward a page (usually 60 lines of text; this is based on a printed page of information), you can use either C-x ] or C-x [ for forward or backward motion, respectively.

Finally, to move to the very top of the file, use M-<, and to move to the bottom, use M->.

Go back into EMACS and locate the cursor. It should be at the very top of the screen:

        _                              A Tale of Two Cities

                                      Preface

When I was acting, with my children and friends, in Mr Wilkie Collins's

drama of The Frozen Deep, I first conceived the main idea of this

story. A strong desire was upon me then, to

embody it in my own person;

and I traced out in my fancy, the state of mind of which it would

necessitate the presentation

to an observant spectator, with particular

care and interest.

As the idea became familiar to me, it gradually shaped itself into its

present form. Throughout its execution, it has had complete posession

of me; I have so far verified what

is done and suffered in these pages,

as that I have certainly done and suffered it all myself.

Whenever any reference (however slight) is made here to the condition

of the French people before or during the Revolution, it is truly made,

on the faith of the most trustworthy

witnesses. It has been one of my hopes to add

——Emacs: dickens.note           (Fundamental)——Top————————————-

Move down four lines by using C-n four times. You should now be sitting on the "d" in "drama":

Preface

When I was acting, with my children and friends, in Mr Wilkie Collins's

[d]rama of The Frozen Deep, I first conceived the main idea of this

story. A strong desire was upon me then, to

embody it in my own person;

and I traced out in my fancy, the state of mind of which it would

Next, move to the end of this sentence by using the M-e command (just like vi, EMACS expects two spaces to separate sentences):

When I was acting, with my children and friends, in Mr Wilkie Collins's

drama of The Frozen Deep, I first conceived the main idea of this

story._ A strong desire was upon me then, to

embody it in my own person;

and I traced out in my fancy, the state of mind of which it would

Now type in the following text: I fought the impulse to write this novel vociferously, but, dear reader, I felt the injustice of the situation too strongly in my breast to deny. Don't press Return or Esc when you're done. The screen should now look similar to this:

drama of The Frozen Deep, I first conceived the main idea of this

story. I fought the impulse to write this novel vociferously, but, dear reader,\

 I felt 

the injustice of the situation too strongly in my breast to deny_  A strong des\

ire was upon me then, to

embody it in my own person;

and I traced out in my fancy, the state of mind of which it would

necessitate the presentation

You can see that EMACS wrapped the line when it became too long (between the words "felt" and "the"), and because the lines are still too long to display, a few of them end with a backslash. The backslash isn't actually a part of the file; with it, EMACS is telling you that those lines are longer than you might expect.

Now try to move back a few letters by pressing Backspace.

Uh-oh! If your system is like mine, the Backspace key doesn't move the cursor back a letter at all. Instead it starts the EMACS help system, where you're suddenly confronted with a screen that looks like this:

You have typed C-h, the help character. Type a Help option:

A  command-apropos.  Give a substring, and see a list of commands

              (functions interactively callable) that contain

              that substring. See also the  apropos  command.

B  dEscribe-bindings. Display table of all key bindings.

C  dEscribe-key-briefly. Type a command key sequence;

              it prints the function name that sequence runs.

F  dEscribe-function. Type a function name and get documentation of it.

I  info. The  info  documentation reader.

K  dEscribe-key. Type a command key sequence;

              it displays the full documentation.

L  view-lossage. Shows last 100 characters you typed.

M  dEscribe-mode. Print documentation of current major mode,

              which dEscribes the commands peculiar to it.

N  view-emacs-news. Shows emacs news file.

S  dEscribe-syntax. Display contents of syntax table, plus explanations

T  help-with-tutorial. Select the Emacs learn-by-doing tutorial.

V  dEscribe-variable. Type name of a variable;

              it displays the variable's documentation and value.

W  where-is. Type command name; it prints which keystrokes

              invoke that command.

—**-Emacs: *Help*                 (Fundamental)——Top————————————-

A B C F I K L M N S T V W C-c C-d C-n C-w or Space to scroll: _

To escape the help screen, press Esc. Your screen should be restored. Notice that the filename has been changed and is now shown as *Help* instead of the actual file. The status line also shows what file you're viewing, but you aren't always viewing the file you want to work with.

The correct keys to move the cursor back a few characters are C-b. Use them to back up. Then use C-f to move forward again to the original cursor location.

Check that the last few lines of the file haven't changed by using the EMACS move-to-end-of-file command M->. (Think of file redirection to remember the file motion commands). Now the screen looks like this:

Whenever any reference (however slight) is made here to the condition

of the French people before or during the Revolution, it is truly made,

on the faith of the most trustworthy

witnesses. It has been one of my hopes to add

something to the popular and picturesque means of

understanding that terrible time, though no one can hope

to add anything to the philosophy of Mr Carlyle's wonderful book.

Tavistock House

November 1859

_

—**-Emacs: dickens.note           (Fundamental)——Bot————————————-

Changing the words of Charles Dickens was fun, so save these changes and quit. If you try to quit the program with C-x C-c, EMACS reminds you that there are unsaved changes:

—**-Emacs: dickens.note           (Fundamental)——Bot————————————-

Save file /users/taylor/dickens.note? (y or n)  _

Pressing y saves the changes, and n quits without saving the changes. If you instead decide to return to the edit session, Esc cancels the action entirely. Pressing n reminds you a second time that the changes are going to be lost if you don't save them.

—**-Emacs: dickens.note           (Fundamental)——Bot————————————-

Modified buffers exist; exit anyway? (yes or no)  _

This time type yes and, finally, you're back on the command line.

Entering text in EMACS is incredibly easy. It's as if the editor is always in insert mode. The price that you pay for this, however, is that just about anything else you do requires Ctrl or Meta sequences: even the Backspace key did something other than what you wanted. (You could fix the problem with key mapping so that pressing that key results in a C-b command, but then you couldn't get to the help information.)

The motion commands are summarized in Table 7.4.

Command


Meaning


M->

Move to end of file.

M-<

Move to beginning of file.

C-v

Move forward a screen.

M-v

Move backward a screen.

C-x ]

Move forward a page.

C-x [

Move backward a page.

C-n

Move to the next line.

C-p

Move to the previous line.

C-a

Move to the beginning of the line.

C-e

Move to the end of the line.

M-e

Move to the end of the sentence.

M-a

Move to the beginning of the sentence.

C-f

Move forward a character.

C-b

Move backward a character.

M-f

Move forward a word.

M-b

Move backward a word.

How to Delete Characters and Words

Inserting text into an EMACS buffer is quite simple, and once you get the hang of it, moving about in the file isn't too bad either. How about deleting text? The series of Ctrl and Meta commands that allow you to insert text are a precursor to all commands in EMACS, and it should come as no surprise that C-d deletes the current character, M-d deletes the next word, M-k deletes the rest of the current sentence, and C-k deletes the rest of the current line. If you have a key on your keyboard labeled DEL, RUBOUT, or Delete, you're in luck, because DEL deletes the previous character, M-DEL deletes the previous word, and C-x DEL deletes the previous sentence.

I have a Delete key, but it's tied to the Backspace function on my system. Every time I press it, it actually sends a C-h sequence to the system, not the DEL sequence. The result is that I cannot use any of these backwards deletion commands.

Restart EMACS with the dickens.note file and move the cursor to the middle of the fifth line (remember, C-n moves to the next line, and C-f moves forward a character). It should look like this:

Preface

When I was acting, with my children and friends, in Mr Wilkie Collins's

drama of The Frozen Deep, I first conceived the main idea of this

story. A strong desire [w]as upon me then, to

embody it in my own person;

and I traced out in my fancy, the state of mind of which it would

necessitate the presentation

to an observant spectator, with particular

Notice that my cursor is on the "w" in "was" on the fifth line here.

Press C-d C-d C-d to remove the word "was." Now simply type came to revise the sentence slightly. The screen should now look like this:

Preface

When I was acting, with my children and friends, in Mr Wilkie Collins's

drama of The Frozen Deep, I first conceived the main idea of this

story. A strong desire came_upon me then, to

embody it in my own person;

and I traced out in my fancy, the state of mind of which it would

necessitate the presentation

to an observant spectator, with particular

Now press DEL once to remove the last letter of the new word and press e to reinsert it. Instead of backing up a character at a time, instead use M-DEL to delete the word just added. The word is deleted, but the spaces on either side of the word are retained.

Preface

When I was acting, with my children and friends, in Mr Wilkie Collins's

drama of The Frozen Deep, I first conceived the main idea of this

story. A strong desire _upon me then, to

embody it in my own person;

and I traced out in my fancy, the state of mind of which it would

necessitate the presentation

to an observant spectator, with particular

Try another word to see if you can get this sentence to sound better. Type crept to see how it reads.

On the other hand, it's probably not good to revise classic stories like A Tale of Two Cities, so the best move is to delete this entire sentence. If you press C-x DEL, will it do the right thing? Remember, C-x DEL deletes the previous sentence. Press C-x DEL and the results are helpful, if not completely what you want to accomplish:

Preface

When I was acting, with my children and friends, in Mr Wilkie Collins's

drama of The Frozen Deep, I first conceived the main idea of this

story. _upon me then, to

embody it in my own person;

and I traced out in my fancy, the state of mind of which it would

necessitate the presentation

to an observant spectator, with particular

That's okay. Now you can delete the second part of the sentence by using the M-k command. Now the screen looks like what you want:

When I was acting, with my children and friends, in Mr Wilkie Collins's

drama of The Frozen Deep, I first conceived the main idea of this

story. _

As the idea became familiar to me, it gradually shaped itself into its

present form. Throughout its execution, it has had complete posession

of me; I have so far verified what

Here's a great feature of EMACS! You just realized that deleting sentences is just as wildly inappropriate as changing words, so you want to undo the last two changes. If you were using vi you'd be stuck, because vi remembers only the last change; but EMACS has that beat. With EMACS, you can back up as many changes as you'd like, usually until you restore the original file. To step backwards, use C-x u.

The first time you press C-x u, the screen changes to this:

When I was acting, with my children and friends, in Mr Wilkie Collins's

drama of The Frozen Deep, I first conceived the main idea of this

story. _upon me then, to

embody it in my own person;

and I traced out in my fancy, the state of mind of which it would

necessitate the presentation

to an observant spectator, with particular

care and interest.

As the idea became familiar to me, it gradually shaped itself into its

present form. Throughout its execution, it has had complete posession

The second time you press it, the screen goes even further back in your revision history:

When I was acting, with my children and friends, in Mr Wilkie Collins's

drama of The Frozen Deep, I first conceived the main idea of this

story. A strong desire crept_upon me then, to

embody it in my own person;

and I traced out in my fancy, the state of mind of which it would

necessitate the presentation

to an observant spectator, with particular

care and interest.

As the idea became familiar to me, it gradually shaped itself into its

present form. Throughout its execution, it has had complete posession

Finally, pressing C-x u three more times causes the original text to be restored:

A Tale of Two Cities

                                      Preface

When I was acting, with my children and friends, in Mr Wilkie Collins's

drama of The Frozen Deep, I first conceived the main idea of this

story. A strong desire [c]ame upon me then, to

embody it in my own person;

and I traced out in my fancy, the state of mind of which it would

necessitate the presentation

to an observant spectator, with particular

care and interest.

As the idea became familiar to me, it gradually shaped itself into its

present form. Throughout its execution, it has had complete posession

of me; I have so far verified what

is done and suffered in these pages,

as that I have certainly done and suffered it all myself.

Whenever any reference (however slight) is made here to the condition

of the French people before or during the Revolution, it is truly made,

on the faith of the most trustworthy

witnesses. It has been one of my hopes to add

—**-Emacs: dickens.note           (Fundamental)——Top————————————-

Undo!

Regrettably, if you don't have a DELETE key, some of the deletion commands will be unavailable to you. Generally, though, EMACS has as many ways to delete text as vi has, if not more. The best feature is that, unlike vi, EMACS remembers changes from the beginning of your editing session. You can always back up as far as you want by using the C-x u undo request.

The delete keys are summarized in Table 7.5.

Command


Meaning


DEL

Delete the previous character.

C-d

Delete the current character.

M-DEL

Delete the previous word.

M-d

Delete the next word.

C-x DEL

Delete the previous sentence.

M-k

Delete the rest of the current sentence.

C-k

Delete the rest of the current line.

C-x u

Undo the last edit change.

Search and Replace in EMACS

Because EMACS reserves the last line of the screen for its own system prompts, searching and replacing is easier than in vi. Moreover, the system prompts for the fields and asks, for each occurrence, whether to change it or not. On the other hand, this command isn't a simple key press or two, but rather it is an example of a named EMACS command.

Searching forward for a pattern is done by pressing C-s and searching backwards with C-r (the mnemonics are search forward and reverse search). To leave the search once you've found what you want, press Esc. To cancel the search, returning to your starting point, use C-g.


WARNING: Unfortunately, you might find that pressing C-s does very strange things to your system. In fact, ^s and ^q are often used as flow control on a terminal, and by pressing the C-s key, you're actually telling the terminal emulator to stop sending information until it sees a C-q. If this happens to you, you need to try to turn off XON/XOFF flow control. Ask your system administrator for help.

Query and replace is really a whole new feature within EMACS. To start a query and replace, use M-x query-replace. EMACS will prompt for what to do next. Once a match is shown, you can type a variety of different commands to affect what happens: y makes the change; n means to leave it as is, but move to the next match; Esc or q quits replace mode; and ! automatically replaces all further occurrences of the pattern without further prompting.

You're still looking at the dickens.note file, and you have moved the cursor to the top-left corner by using M-<. Somewhere in the file is the word "Revolution," but you're not sure where. Worse, every time you press C-s, the terminal freezes up until you press C-q because of flow control problems. Instead of searching forward, search backward by moving the cursor to the bottom of the file with M-> and then pressing C-r.

——Emacs: dickens.note           (Fundamental)——Bot————————————


I-search backward:

As you type each character of the pattern Revolution, the cursor dances backward, matching the pattern as it grows longer and longer, until EMACS finds the word you seek:

Whenever any reference (however slight) is made here to the condition

of the French people before or during the [R]evolution, it is truly made,

on the faith of the most trustworthy

witnesses. It has been one of my hopes to add

something to the popular and picturesque means of

understanding that terrible time, though no one can hope

to add anything to the philosophy of Mr Carlyle's wonderful book.

Tavistock House

November 1859

——Emacs: dickens.note           (Fundamental)——Bot————————————-

I-search backward: Revol

Now try the query-replace feature. Move to the top of the file with M-<, and then type in M-x, which causes the notation to show up on the bottom status line:

of the French people before or during the Revolution, it is truly made,

on the faith of the most trustworthy

witnesses. It has been one of my hopes to add

—**-Emacs: dickens.note           (Fundamental)——Top97Ä———————————-

M-x _

Then type the words query-replace and press Return. EMACS understands that you want to find all occurrences of a pattern and replace them with another. EMACS changes the prompt to this:

of the French people before or during the Revolution, it is truly made,

on the faith of the most trustworthy

witnesses. It has been one of my hopes to add

—**-Emacs: dickens.note           (Fundamental)——Top————————————-

Query replace: _

Now type in the word that you want to replace. To cause confusion in the file, change French to Danish. Maybe A Tale of Two Cities really takes place in London and Copenhagen! To do this, type French and press Return. The prompt again changes to this:

of the French people before or during the Revolution, it is truly made,

on the faith of the most trustworthy

witnesses. It has been one of my hopes to add

—**-Emacs: dickens.note           (Fundamental)——Top————————————-

Query replace French with: _

Enter Danish and again press Return.

as that I have certainly done and suffered it all myself.

Whenever any reference (however slight) is made here to the condition

of the French_people before or during the Revolution, it is truly made,

on the faith of the most trustworthy

witnesses. It has been one of my hopes to add

—**-Emacs: dickens.note           (Fundamental)——Top————————————-

Query replacing French with Danish:

It may not be completely obvious, but EMACS has found a match (immediately before the cursor) and is prompting you for what to do next. The choices here are summarized in Table 7.6.

Command


Meaning


y

Change this occurrence of the pattern.

n

Don't change this occurrence, but look for another.

q

Don't change. Leave query-replace completely (you can also use Esc for this function).

!

Change this occurrence and all others in the file.

Opt to make this change, and all other possible changes in the file, by pressing !. The screen changes to tell you that there were no more occurrences:

Whenever any reference (however slight) is made here to the condition

of the Danish_people before or during the Revolution, it is truly made,

on the faith of the most trustworthy

witnesses. It has been one of my hopes to add

—**-Emacs: dickens.note           (Fundamental)——Top————————————

Done

Searching in EMACS is awkward, due in particular to the flow control problems that you may incur because of your terminal. However, searching and replacing with the query-replace command is much better and more powerful than the vi alternative. Your assessment of EMACS all depends on what features you prefer.

Using the EMACS Tutorial and Help System

Unlike vi and, indeed, most of UNIX, EMACS includes its own extensive built-in documentation and a tutorial to help you learn about using the package. As noted earlier, the entire help system is accessed by pressing C-h. Pressing C-h three times brings up the general help menu screen. There is also an information browser called info (accessed by pressing C-h i) and a tutorial system you can start by pressing C-h t.

EMACS enthusiasts insist that the editor is modeless, but in fact it does have modes of its own. You used one just now, the query-replace mode. To obtain help on the current mode that you're working in, you can use C-h m.

Press C-h C-h C-h, and the entire screen is replaced with this:

You have typed C-h, the help character. Type a Help option:

A  command-apropos.  Give a substring, and see a list of commands

              (functions interactively callable) that contain

              that substring. See also the  apropos  command.

B  dEscribe-bindings. Display table of all key bindings.

C  dEscribe-key-briefly. Type a command key sequence;

              it prints the function name that sequence runs.

F  dEscribe-function. Type a function name and get documentation of it.

I  info. The  info  documentation reader.

K  dEscribe-key. Type a command key sequence;

              it displays the full documentation.

L  view-lossage. Shows last 100 characters you typed.

M  dEscribe-mode. Print documentation of current major mode,

              which dEscribes the commands peculiar to it.

N  view-emacs-news. Shows emacs news file.

S  dEscribe-syntax. Display contents of syntax table, plus explanations

T  help-with-tutorial. Select the Emacs learn-by-doing tutorial.

V  dEscribe-variable. Type name of a variable;

              it displays the variable's documentation and value.

W  where-is. Type command name; it prints which keystrokes

              invoke that command.

—**-Emacs: *Help*                 (Fundamental)——Top————————————

A B C F I K L M N S T V W C-c C-d C-n C-w or Space to scroll: _

What now? There are actually 17 different options from this point, as shown in Table 7.7.

Command


Meaning


A

List all commands matching the specified word.

B

List all key mappings (EMACS calls them key bindings).

C

DEscribe any key sequence pressed, instead of doing it.

F

DEscribe the specified function.

I

Start up the info browser.

K

Fully dEscribe the result of a particular key sequence.

L

Show the last 100 characters you typed.

M

DEscribe the current mode you're in.

S

List a command syntax table.

T

Start the EMACS tutorial.

V

Define and dEscribe the specified variable.

W

Indicate what keystroke invokes a particular function.

C-c

EMACS copyright and distribution information.

C-d

EMACS ordering information.

C-n

Recent EMACS changes.

C-w

EMACS warranty.

Choose K and then press M-< to see what that command really does. The first thing that happens after you enter K is that the table of help information vanishes, to be replaced by the original text. Then the prompt appears along the bottom:

of the Danish_people before or during the Revolution, it is truly made,

on the faith of the most trustworthy

witnesses. It has been one of my hopes to add

—**-Emacs: dickens.note           (Fundamental)——Top————————————-

DEscribe key:-

Pressing M-< brings up the desired information:

A Tale of Two Cities

                                      Preface

When I was acting, with my children and friends, in Mr Wilkie Collins's

drama of The Frozen Deep, I first conceived the main idea of this

story. A strong desire came upon me then, to

embody it in my own person;

and I traced out in my fancy, the state of mind of which it would

necessitate the presentation

to an observant spectator, with particular

——Emacs: dickens.note~          (Fundamental)——Top————————————-

beginning-of-buffer:

Move point to the beginning of the buffer; leave mark at previous position.

With arg N, put point N/10 of the way from the true beginning.

Don't use this in Lisp programs!

(goto-char (point-min)) is faster and does not set the mark.

——Emacs: *Help*                 (Fundamental)——All————————————

Type C-x 1 to remove help window.

A quick C-x 1 removes the help information when you're done with it.

There is a considerable amount of help available in the EMACS editor. If you're interested in learning more about this editor, the online tutorial is a great place to start. Try C-h t to start it and go from there.

Working with Other Files

By this point it should be no surprise that there are about a million commands available within the EMACS editor, even though it can be a bit tricky to get to them. There are many file-related commands too, but this section focuses on just a few essential commands so you can get around in the program. The EMACS help system can offer lots more. (Try using C-h a file to find out what functions are offered in your version of the program.)

To add the contents of a file to the current edit buffer, use the command C-x i. It will prompt for a filename. Pressing C-x C-w prompts for a file to write the buffer into, rather than the default file. To save to the default file, use C-x C-s (that is, if you can: the C-s might again hang you up, just as it did when you tried to use it for searching). If that doesn't work, you can always use the alternative C-x s. To move to another file, use C-x C-f. (EMACS users never specify more than one filename on the command line. They use C-x C-f to move between files instead). What's nice is that when you use the C-x C-f command, you load the contents of that file into another buffer, so you can zip quickly between files by using the C-x b command to switch buffers.

Without leaving EMACS, press C-x C-f to read another file into the buffer. The system then prompts you as follows:

of the Danish people before or during the Revolution, it is truly made,

on the faith of the most trustworthy

witnesses. It has been one of my hopes to add

——Emacs: dickens.note           (Fundamental)——Top————————————

Find file: ~/ _

Type buckaroo and the editor opens up a new buffer, moving you to that file:

 [I] found myself stealing a peek at my own watch and overhead

General Catbird's

aide give him the latest.

"He's not even here," went the conversation.

"Banzai."

"Where the hell is he?"

"At the hospital in El Paso."

"What? Why weren't we informed? What's wrong with him?"

——Emacs: buckaroo               (Fundamental)——All————————————-

Now flip back to the other buffer with C-x b. When you enter that command, however, it doesn't automatically move you there. Instead it offers this prompt:

—**-Emacs: buckaroo               (Fundamental)——All————————————-

Switch to buffer: (default dickens.note) _

When you press ?, you receive a split screen indicating what the possible answers are:

I found myself stealing a peek at my own watch and overhead

General Catbird's

aide give him the latest.

"He's not even here," went the conversation.

"Banzai."

"Where the hell is he?"

"At the hospital in El Paso."

"What? Why weren't we informed? What's wrong with him?"

—**-Emacs: buckaroo               (Fundamental)——All————————————

Possible completions are:

*Buffer List*                      *Help*

*scratch*                          buckaroo

dickens.note

——Emacs:  *Completions*         (Fundamental)——All————————————

Switch to buffer: (default dickens.note) _

The default is okay, so press Return and go back to the Dickens file. One more C-x b; this time the default is buckaroo, so again press Return to move back.

You're in the buckaroo file, and you want to see what happens if you read dickens.note into this file. This is done easily. Move the cursor to the end of the file with M-> and then press C-x i, answering dickens.note to the prompt Insert file: ~/. Pressing Return yields the following screen display:

I found myself stealing a peek at my own watch and overhead

General Catbird's

aide give him the latest.

"He's not even here," went the conversation.

"Banzai."

"Where the hell is he?"

"At the hospital in El Paso."

"What? Why weren't we informed? What's wrong with him?"

                                A Tale of Two Cities

                                      Preface

When I was acting, with my children and friends, in Mr Wilkie Collins's

drama of The Frozen Deep, I first conceived the main idea of this

story. A strong desire came upon me then, to

embody it in my own person;

and I traced out in my fancy, the state of mind of which it would

necessitate the presentation

to an observant spectator, with particular

care and interest.

As the idea became familiar to me, it gradually shaped itself into its

present form. Throughout its execution, it has had complete posession

—**-Emacs: buckaroo               (Fundamental)——Top————————————-

It's time to quit and split. To do this, press C-x s and wait for an EMACS prompt or two. The first one displayed is this:

As the idea became familiar to me, it gradually shaped itself into its

present form. Throughout its execution, it has had complete posession

—**-Emacs: buckaroo               (Fundamental)——Top————————————

Save file /users/taylor/buckaroo? (y or n) _

Answer y to save this muddled file. It returns you to the top of the file, and a quick C-x C-c drops you back to the system prompt.

This has only scratched the surface of EMACS, a fantastically powerful editor. The best way to learn more is to work through the online tutorial in the editor or to peruse the information available in the help system.

You have now learned quite a bit about the EMACS editor. Some capabilities exceed those of the vi editor, and some are considerably more confusing. Which of these editors you choose is up to you, and your choice should be based on your own preferences for working on files. You should spend some time working with the editor you prefer to make sure you can create simple files and modify them without any problems.

The sed Command

In this section, you get to put on your programming hat and learn about a powerful command that can be customized infinitely and used for a wide variety of tasks. sed is a program for modifying information traveling through a UNIX pipeline.

Changing Things En Route with sed

I'm willing to bet that when you read about learning some UNIX programming tools in this section, you got anxious, your palms started to get sweaty, your fingers shook, and the little voice in your head said, "It's too late! We can use a pad and paper! We don't need computers at all!"

Don't panic.

If you think about it, you've been programming all along in UNIX. When you enter a command to the shell, you're programming the shell to immediately perform the task specified. When you specify file redirection or build a pipe, you're really writing a small UNIX program that the shell interprets and acts upon. Frankly, when you consider how many different commands you now know and how many different flags there are for each of those commands, you've got quite a set of programming tools under your belt already. So onward!

With a | symbol called a pipe, and commands tied together called pipelines, is it any wonder that the information flowing down a pipeline is called a stream? For example, the command cat test | wc means that the cat command opens the file test and streams it to the wc program, which counts the number of lines, words, and characters therein.

To modify the information in a pipeline, then, it seems reasonable to use a stream editor, and that's exactly what the sed command is! In fact, its name comes from its function: stream editor.

Here's the bad news. The sed command is built on an old editor called ed, the same editor that's responsible for the grep command. Remember? The global/regular expression/print eventually became grep. A microcosm of UNIX itself, commands to sed are separated by a semicolon.

There are many different sed commands, but this section focuses on using sed to substitute one pattern for another and to extract ranges of lines from a file. The general format of the substitution command is: s/old/new/flags, where old and new are the patterns you're working with, s is the abbreviation for the substitute command, and the two most helpful flags are g (to replace all occurrences globally on each line) and n (to tell sed to replace only the first n occurrences of the pattern). By default, lines are listed to the screen, so a sed expression like 10q will cause the program to list the first 10 lines and then quit (making it an alternative to the command head -10). Deletion is similar: the command is prefaced by one or two addresses in the file, reflecting a request to delete either all lines that match the specified address or all in the range of first to last.

The format of the sed command is sed followed by the expression in quotes and, optionally, the name of the file to read for input.

Here's an easy example. Use grep to extract some lines from the /etc/passwd file and replace all colons with a single space. The format of this command is to substitute each occurrence of : with a space, or s/:/ /:

% grep taylor /etc/passwd | sed -e 's/:/ /'

taylorj ?:1048:1375:James Taylor:/users/taylorj:/bin/csh

mtaylor ?:769:1375:Mary Taylor:/users/mtaylor:/usr/local/bin/tcsh

dataylor ?:375:518:Dave Taylor,,,,:/users/dataylor:/usr/local/lib/msh

taylorjr ?:203:1022:James Taylor:/users/taylorjr:/bin/csh

taylorrj ?:662:1042:Robert Taylor:/users/taylorrj:/bin/csh

taylorm ?:869:1508:Melanie Taylor:/users/taylorm:/bin/csh

taylor ?:1989:1412:Dave Taylor:/users/taylor:/bin/csh

This doesn't quite do what you want. You neglected to append the global instruction to the sed command to ensure that it would replace all occurrences of the pattern on each line. Try it again, this time adding a g to the instruction.

% grep taylor /etc/passwd | sed -e 's/:/ /g'

taylorj ? 1048 1375 James Taylor /users/taylorj /bin/csh

mtaylor ? 769 1375 Mary Taylor /users/mtaylor /usr/local/bin/tcsh

dataylor ? 375 518 Dave Taylor /users/dataylor /usr/local/lib/msh

taylorjr ? 203 1022 James Taylor /users/taylorjr /bin/csh

taylorrj ? 662 1042 Robert Taylor /users/taylorrj /bin/csh

taylorm ? 869 1508 Melanie Taylor /users/taylorm /bin/csh

taylor ? 1989 1412 Dave Taylor /users/taylor /bin/csh

A more sophisticated example of substitution with sed is to modify names, replacing all occurrences of Taylor with Tailor:

% grep taylor /etc/passwd | sed -e 's/Taylor/Tailor/g'

taylorj:?:1048:1375:James Tailor:/users/taylorj:/bin/csh

mtaylor:?:769:1375:Mary Tailor:/users/mtaylor:/usr/local/bin/tcsh

dataylor:?:375:518:Dave Tailor:/users/dataylor:/usr/local/lib/msh

taylorjr:?:203:1022:James Tailor:/users/taylorjr:/bin/csh

taylorrj:?:662:1042:Robert Tailor:/users/taylorrj:/bin/csh

taylorm:?:869:1508:Melanie Tailor:/users/taylorm:/bin/csh

taylor:?:1989:1412:Dave Tailor:/users/taylor:/bin/csh

The colons have returned, which is annoying. Use the fact that a semicolon can separate multiple sed commands on the same line and try it one more time:

% grep taylor /etc/passwd | sed -e 's/Taylor/Tailor/g;s/:/ /g'

taylorj ? 1048 1375 James Tailor /users/taylorj /bin/csh

mtaylor ? 769 1375 Mary Tailor /users/mtaylor /usr/local/bin/tcsh

dataylor ? 375 518 Dave Tailor /users/dataylor /usr/local/lib/msh

taylorjr ? 203 1022 James Tailor /users/taylorjr /bin/csh

taylorrj ? 662 1042 Robert Tailor /users/taylorrj /bin/csh

taylorm ? 8692 1508 Melanie Tailor /users/taylorm /bin/csh

taylor ? 1989 1412 Dave Tailor /users/taylor /bin/csh

This last sed command can be read as "each time you encounter the pattern Taylor replace it with Tailor, even if it occurs multiple times on each line. Then, each time you encounter a colon, replace it with a space."

Another example of using sed is to rewrite the output of the who command to be a bit more readable. Consider the results of entering who on your system:

% who

strawmye ttyAc   Nov 21 19:01

eiyo     ttyAd   Nov 21 17:40

tzhen    ttyAg   Nov 21 19:13

kmkernek ttyAh   Nov 17 23:22

macedot  ttyAj   Nov 21 20:41

rpm      ttyAk   Nov 21 20:40

ypchen   ttyAl   Nov 21 18:20

kodak    ttyAm   Nov 21 20:43

The output is a bit confusing; sed can help:

% who | sed 's/tty/On Device /;s/Nov/Logged in November/'

strawmye On Device Ac   Logged in November 21 19:01

eiyo     On Device Ad   Logged in November 21 17:40

tzhen    On Device Ag   Logged in November 21 19:13

kmkernek On Device Ah   Logged in November 17 23:22

macedot  On Device Aj   Logged in November 21 20:41

rpm      On Device Ak   Logged in November 21 20:40

ypchen   On Device Al   Logged in November 21 18:20

kodak    On Device Am   Logged in November 21 20:43

This time, each occurrence of the letters tty is replaced with the phrase On Device. Similarly, Nov is replaced with Logged in November.

The sed command can also be used to delete lines in the stream as it passes. The simplest version is to specify only the command:

% who | sed 'd'

%

There's no output because the command matches all lines and deletes them. Instead, to delete just the first line, simply preface the d command with that line number:

% who | sed '1d'

eiyo     ttyAd   Nov 21 17:40

tzhen    ttyAg   Nov 21 19:13

kmkernek ttyAh   Nov 17 23:22

macedot  ttyAj   Nov 21 20:41

rpm      ttyAk   Nov 21 20:40

ypchen   ttyAl   Nov 21 18:20

kodak    ttyAm   Nov 21 20:43

To delete more than just the one line, specify the first and last lines to delete, separating them with a comma. The following deletes the first three lines:

% who | sed '1,3d'

macedot  ttyAj   Nov 21 20:41

rpm      ttyAk   Nov 21 20:40

ypchen   ttyAl   Nov 21 18:20

kodak    ttyAm   Nov 21 20:43

There's more to deletion than that. You can also specify patterns by surrounding them with slashes, just the substitution pattern. To delete the entries in the who output between eiyo and rpm, the following would work:

% who | head -15 | sed '/eiyo/,/rpm/d'

root     console Nov  9 07:31

rick     ttyAa   Nov 21 20:58

brunnert ttyAb   Nov 21 20:56

ypchen   ttyAl   Nov 21 18:20

kodak    ttyAm   Nov 21 20:43

wh       ttyAn   Nov 21 20:33

klingham ttyAp   Nov 21 19:55

linet2   ttyAq   Nov 21 20:17

mdps     ttyAr   Nov 21 20:11

You can use patterns in combination with numbers too, so if you wanted to delete the text from the first line to the line containing kmkernek, here's how you could do it:

% who | sed '1,/kmkernek/d'

macedot  ttyAj   Nov 21 20:41

rpm      ttyAk   Nov 21 20:40

ypchen   ttyAl   Nov 21 18:20

kodak    ttyAm   Nov 21 20:43

Another aspect of sed is that the patterns are actually regular expressions. Don't be intimidated, though. If you understood the * and ? in filename wildcards, you've learned the key lesson of regular expressions: special characters can match zero or more letters in the pattern. Regular expressions are slightly different from shell patterns, because regular expressions more powerful (though more confusing). Instead of using the ? to match a character, use the . character.

Within this context, it's rare that you need to look for patterns sufficiently complex to require a full regular expression, which is definitely good news. The only two characters you want to remember for regular expressions are ^, which is the imaginary character before the first character of each line, and $, which is the character after the end of each line.

What does this mean? It means that you can use sed to list everyone reported by who that doesn't have s as the first letter of his or her account. You can also eliminate all blank lines from a file with sed. Return to the testme file:

% cat testme

Archives/               OWL/                    keylime.pie

InfoWorld/              bin/                    src/

Mail/                   bitnet.mailing-lists.Z  temp/

News/                   drop.text.hqx           testme

Archives/               OWL/                    keylime.pie

InfoWorld/              bin/                    src/

Mail/                   bitnet.mailing-lists.Z  temp/

News/                   drop.text.hqx           testme

Archives/               OWL/                    keylime.pie

InfoWorld/              bin/                    src/

Mail/                   bitnet.mailing-lists.Z  temp/

News/                   drop.text.hqx           testme

Now use sed to clean up this output.

% sed '/^$/d' < testme

Archives/               OWL/                    keylime.pie

InfoWorld/              bin/                    src/

Mail/                   bitnet.mailing-lists.Z  temp/

News/                   drop.text.hqx           testme

Archives/               OWL/                    keylime.pie

InfoWorld/              bin/                    src/

Mail/                   bitnet.mailing-lists.Z  temp/

News/                   drop.text.hqx           testme

Archives/               OWL/                    keylime.pie

InfoWorld/              bin/                    src/

Mail/                   bitnet.mailing-lists.Z  temp/

News/                   drop.text.hqx           testme

%

These commands can be used in combination, of course; one sed command can be used to remove all blank lines, all lines that contain the word keylime, and substitute BinHex for each occurrence of hqx:

% cat testme | sed '/^$/d;/keylime/d;s/hqx/BinHex/g'

InfoWorld/              bin/                    src/

Mail/                   bitnet.mailing-lists.Z  temp/

News/                   drop.text.BinHex                testme

InfoWorld/              bin/                    src/

Mail/                   bitnet.mailing-lists.Z  temp/

News/                   drop.text.BinHex                testme

InfoWorld/              bin/                    src/

Mail/                   bitnet.mailing-lists.Z  temp/

News/                   drop.text.BinHex                testme

%

If you've ever spent any time on an electronic network, you've probably seen either electronic mail or articles wherein the author responds to a previous article. Most commonly, all the lines of the original message are included, each prefixed by >. It turns out that sed is the appropriate tool either to add a prefix to a group of lines or to remove a prefix from lines in a file:

% cat << EOF > sample

Hey Tai! I've been looking for a music CD and none of

the shops around here have a clue about it. I was

wondering if you're going to have a chance to get into

Tower Records in the next week or so?

EOF

%

% sed 's/^/> /' < sample > sample2

% cat sample2

> Hey Tai! I've been looking for a music CD and none of

> the shops around here have a clue about it. I was

> wondering if you're going to have a chance to get into

> Tower Records in the next week or so?

%

% cat sample2 | sed 's/^> //'

Hey Tai! I've been looking for a music CD and none of

the shops around here have a clue about it. I was

wondering if you're going to have a chance to get into

Tower Records in the next week or so?

%

Recall that the caret (^) signifies the beginning of the line, so the first invocation of sed searches for the beginning of each line and replaces it with >, saving the output to the file sample2. The second use of sed—wherein you remove the prefix—does the opposite search, finding all occurrences of "> " that are at the beginning of a line and replacing them with a null pattern (which is what you have when you have two slash delimiters without anything between them).

I've only scratched the surface of the sed command here. It's one of those commands where the more you learn about it, the more powerful you realize it is. But, paradoxically, the more you learn about it, the more you'll really want a graphical interface to simplify your life.


NOTE: The only sed command I use is substitution. I figure that matching patterns is best done with grep, and it's very rare that I need to delete specific lines from a file anyway. One helpful tip is that sed can be used to delete from the first line of a file to a specified pattern, meaning that it can easily be used to strip headers from an electronic mail message. Specify the pattern 1,/^$/d.

Previous Page TOC Next Page Home