home | O'Reilly's CD bookshelfs | FreeBSD | Linux | Cisco | Cisco Exam  


Learning the Korn Shell

Learning the Korn ShellSearch this book
Previous: 2.2 The History File Chapter 2
Command-line Editing
Next: 2.4 Vi Editing Mode
 

2.3 Emacs Editing Mode

If you are an emacs user, you will find it most useful to think of emacs editing mode as a simplified, non-customizable [5] emacs with a single, one-line window. All of the basic commands are available for cursor motion, cut and paste, and search.

[5] The public domain Korn shell and bash have emacs-modes that are customizable. See Appendix A, Related Shells .

2.3.1 Basic Commands

Emacs-mode uses control keys for the most basic editing functions. If you aren't familiar with emacs , you can think of these as extensions of the rudimentary "erase" character (usually backspace or DEL ) that UNIX provides through its interface to users' terminals. In fact, emacs-mode figures out what your erase character is and uses that as its delete-backward key. For the sake of consistency, we'll assume your erase character is DEL from now on; if it is [CTRL-H] or something else, you will need to make a mental substitution. The most basic control-key commands are shown in Table 2.1 .

NOTE: (Important: remember that typing [CTRL-D] when your command line is empty may log you off!)

The basic finger habits of emacs-mode are easy to learn, but they do require that you assimilate a couple of concepts that are peculiar to the emacs editor.

The first of these is the use of [CTRL-B] and [CTRL-F] for backward and forward cursor motion. These keys have the advantage of being obvious mnemonics, but many people would rather use the arrow keys that are on just about every keyboard nowadays.

Table 2.1: Basic emacs-mode Commands
Command Description
[CTRL-B] Move backward one character (without deleting)
[CTRL-F] Move forward one character
DEL Delete one character backward
[CTRL-D] Delete one character forward
[CTRL-Y] Retrieve ("yank") last item deleted

Unfortunately, emacs-mode doesn't use the arrow keys, because the codes that they transmit to the computer aren't completely standardized; emacs-mode was designed to work on the widest variety of terminals possible without needing to do the kind of heavy-duty customization that the full emacs does. Just about the only hardware requirement of emacs-mode is that the SPACE character overwrite the character on top of which it is typed.

In emacs-mode, the point (sometimes also called dot ) is an imaginary place just to the left of the character the cursor is on. In the command descriptions in Table 2.1 , some say "forward" while others say "backward." Think of forward as "to the right of point" and backward as "to the left of point."

For example, let's say you type in a line and, instead of typing RETURN , you type [CTRL-B] and hold it down so that it repeats. The cursor will move to the left until it is over the first character on the line, like this:

$ f
grep -l Bob < ~pete/wk/names

Now the cursor is on the f , and point is at the beginning of the line, just before the f . If you type DEL , nothing will happen because there are no characters to the left of point. However, if you press [CTRL-D] (the "delete character forward" command) you will delete the first letter:

$ g
rep -l Bob < ~pete/wk/names

Point is still at the beginning of the line. If this were the desired command, you could hit RETURN now and run it; you don't need to move the cursor back to the end of the line. However, if you wanted to, you could type [CTRL-F] repeatedly to get there:

$ grep -l Bob < ~pete/wk/names 

At this point, typing [CTRL-D] wouldn't do anything, but hitting DEL would erase the final s . If you type DEL and decide you want the s back again, just press [CTRL-Y] to yank it back. If you think this example is silly, you're right in this particular case, but bear in mind that [CTRL-Y] undoes the last delete command of any kind, including the delete-word and delete-line commands that we will see shortly. [6]

[6] emacs users should note that this usage of [CTRL-Y] is different from the full editor, which doesn't save character deletes.

2.3.2 Word Commands

The basic commands are really all you need to get around a command line, but a set of more advanced commands lets you do it with fewer keystrokes. These commands operate on words rather than single characters; emacs-mode defines a word to be a sequence of one or more alphanumeric characters.

The word commands are shown in Table 2.2 . Whereas the basic commands are all single characters, these consist of two keystrokes, ESC followed by a letter. You will notice that the command ESC X , where X is any letter, often does for a word what [CTRL-] X does for a single character. The multiplicity of choices for delete-word-backward arises from the fact that your erase character could be either [CTRL-H] or DEL.

Table 2.2: Emacs-mode Word Commands
Command Description
ESC b Move one word backward
ESC f Move one word forward
ESC DEL Delete one word backward
ESC h Delete one word backward
ESC [CTRL-H] Delete one word backward
ESC d Delete one word forward

To return to our example: if we type ESC b, point will move back a word. Since / is not an alphanumeric character, emacs-mode will stop there:

$ grep -l Bob < ~pete/wk/n
ames

The cursor is on the n in names , and point is between the / and the n . Now let's say we want to change the -l option of this command from Bob to Dave . We need to move back on the command line, so we type ESC b two more times. This gets us here:

$ grep -l Bob < ~p
ete/wk/names

If we type ESC b again, we end up at the beginning of Bob :

$ grep -l B
ob < ~pete/wk/names

Why? Remember that a word is defined as a sequence of alphanumeric characters only; therefore < is not a word, and the next word in the backward direction is Bob . We are now in the right position to delete Bob , so we type ESC d and get:

$ grep -l  
< ~pete/wk/names

Now we can type in the desired argument:

$ grep -l Dave 
< ~pete/wk/names

The [CTRL-Y] "undelete" command will retrieve an entire word, instead of a character, if the word was the last thing deleted.

2.3.3 Line Commands

There are still more efficient ways of moving around a command line in emacs-mode. A few commands deal with the entire line; they are shown in Table 2.3 .

Table 2.3: Emacs-mode Line Commands
Command Description
[CTRL-A] Move to beginning of line
[CTRL-E] Move to end of line
[CTRL-K] Delete ("kill") forward to end of line
[CTRL-C] Capitalize character after point

[CTRL-C] is often the "interrupt" key that UNIX provides through its interface to your terminal. If this is the case, [CTRL-C] in emacs-mode will erase the entire line, as if [CTRL-A] and [CTRL-K] were pressed. On systems where the interrupt key is set to something else (often DEL ), [CTRL-C] capitalizes the current character.

Using [CTRL-A] , [CTRL-E] , and [CTRL-K] should be straightforward. Remember that [CTRL-Y] will always undelete the last thing deleted; if you use [CTRL-K] , that could be quite a few characters.

2.3.4 Moving Around in the History File

Now we know how to get around the command line efficiently and make changes. But that doesn't address the original issue of recalling previous commands by accessing the history file. Emacs-mode has several commands for doing this, summarized in Table 2.4 .

Table 2.4: Emacs-mode Commands for Moving Through the History File
Command Description
[CTRL-P] Move to previous line
[CTRL-N] Move to next line
[CTRL-R] Search backward
ESC < Move to first line of history file
ESC > Move to last line of history file

[CTRL-P] is by far the one you will use most often-it's the "I made a mistake, let me go back and fix it" key. You can use it as many times as you wish to scroll back through the history file. If you want to get back to the last command you entered, you can hold down [CTRL-N] until the Korn shell beeps at you, or just type ESC >. As an example, you hit RETURN to run the command above, but you get an error message telling you that your option letter was incorrect. You want to change it without retyping the whole thing. First, you would type [CTRL-P] to recall the bad command. You get it back with point at the end:

$ grep -l Dave < ~pete/wk/names 
 

After [CTRL-A] , ESC f, two [CTRL-F] s, and [CTRL-D] , you have:

$ grep - 
Dave < ~pete/wk/names

You decide to try -s instead of -l , so you type s and hit RETURN. You get the same error message, so you give up and look it up in the manual. You find out that the command you want is fgrep -not grep -after all. You sigh heavily and go back and find the fgrep command you typed in an hour ago. To do this, you type [CTRL-R] ; whatever was on the line will disappear and be replaced by ^R . Then type fgrep , and you will see this:

$ ^Rfgrep

Hit RETURN, and the shell will search backwards through the history file for a line containing "fgrep". If it doesn't find one, it will beep. But if it finds one, it will display it, and your "current line" will be that line (i.e., you will be somewhere in the middle of the history file, not at the end as usual):

$ fgrep -l Bob < ~pete/wk/names 

Typing [CTRL-R] without an argument (i.e., just [CTRL-R] followed by RETURN) causes the shell to repeat your last backward search. If you try the fgrep command by hitting RETURN again, two things will happen. First, of course, the command will run. Second, this line will be entered into the history file at the end, and your "current line" will be at the end as well. You will no longer be in the middle of the history file. [CTRL-R] may not work properly on some versions of UNIX, because it is also the default setting for the "reprint" function of the terminal interface. (It works correctly on all the versions we've tried.) If you press [CTRL-R] and see the command line reprinted, you may want to consider changing the terminal interface's "reprint" key. See the section on stty in Chapter 8 .

[CTRL-P] and [CTRL-R] are clearly the most important emacs-mode commands that deal with the history file; you might use [CTRL-N] occasionally. The others are less useful, and we suspect that they were mainly included for compatibility with the full emacs editor.

emacs users should also note that the full editor's "deluxe" search capabilities, such as incremental and regular expression search, are not available in the Korn shell's emacs-mode - with one minor exception: if you use [CTRL-R] and precede your search string with a ^ (caret character), it will match only commands that have the search string at the beginning of the line.

2.3.5 Filename Completion and Expansion

One of the most powerful (and typically underused) features of emacs-mode is its filename completion facility, inspired by similar features in the full emacs editor, the C shell, and (originally) the old DEC TOPS-20 operating system.

The premise behind filename completion is that when you need to type a filename, you should not have to type more than is necessary to identify the file unambiguously. This is an excellent feature; there is an analogous one in vi-mode. We recommend that you get it under your fingers, since it will save you quite a bit of typing.

There are three commands in emacs-mode that relate to filename completion. The most important is ESC ESC . [7] When you type in a word of text followed by ESC ESC , the Korn shell will attempt to complete the name of a file in the current directory. Then one of four things can happen:

[7] emacs users can think of this as analogous to minibuffer completion with the TAB key.

  1. If there is no file whose name begins with the word, the shell will beep and nothing further will happen.

  2. If there is exactly one way to complete the filename and the file is a regular file, the shell will type the rest of the filename and follow it with a space so you can type in more command arguments.

  3. If there is exactly one way to complete the filename and the file is a directory, the shell will complete the filename and follow it with a slash.

  4. If there is more than one way to complete the filename, the shell will complete out to the longest common prefix among the available choices.

For example, assume you have a directory with the files program.c and problem.c . You want to compile the first of these by typing cc program.c . You type cc pr followed by ESC ESC . This is not an unambiguous prefix, since the prefix "pro" is common to both filenames, so the shell only completes out to cc pro . You need to type more letters to disambiguate, so you type g and hit ESC ESC again. Then the shell completes out to "cc program.c ", leaving the extra space for you to type in other filenames or options.

A related command is ESC * , which expands the prefix to all possible choices. ESC * acts like the standard * shell wildcard character except that it expands the choices for you to see and does not execute the command. In the above example, if you type ESC * instead of ESC ESC , the shell will expand to "cc problem.c program.c ". If you type ESC = instead of ESC * , you will see a numbered list of expansions printed to standard error.

2.3.6 Miscellaneous Commands

Several miscellaneous commands complete emacs editing mode; they are shown in Table 2.5 .

Table 2.5: Emacs-mode Miscellaneous Commands
Command Description
[CTRL-J] Same as RETURN
[CTRL-L] Redisplay the line
[CTRL-M] Same as RETURN
[CTRL-O] Same as RETURN, then display next line in history file
[CTRL-T]

Transpose two characters to the right of point and move point forward by one[8]

[CTRL-U] Repeat the following command four times
[CTRL-V] Print the version of the Korn shell
[CTRL-W]

Delete ("wipe") all characters between point and "mark". "Mark" is discussed later in this section.

[CTRL-X] [CTRL-X] Exchange point and mark
[CTRL-] [ Same as ESC (most keyboards)
[CTRL-] ] x

Search forward on current line for x, where x is any character

ESC Change word after point to all capital letters
ESC l Change word after point to all lowercase letters
ESC p

Save all characters between point and mark as if they were deleted

ESC . Insert last word in previous command line after point
ESC _ Same as above
ESC CTRL -]x Search backward for x , where x is any character
ESC SPACE Set mark at point
ESC # Insert line in history file for future editing

[8] [CTRL-T] behaves slightly differently if you put set -o gmacs (instead of emacs ) in your .profile . In this case, it will transpose the two characters to the left of point, leaving point unmoved. This is the only difference between emacs and gmacs modes; the latter conforms to the James Gosling version of the emacs editor (a.k.a. Unipress emacs ). Note: neither of these behaves like [CTRL-T] in GNU emacs , which transposes the characters on either side of point.

Several of these commands may clash with terminal interface control keys on your system. [CTRL-U] is the default key for "kill line" on most versions of UNIX. BSD-derived systems use [CTRL-V] and [CTRL-W] as default settings for the "quote next character" and "word erase" terminal interface functions respectively. [CTRL-V] is particularly confusing, since it is meant to override other terminal interface control keys but has no effect on emacs-mode commands.

A few miscellaneous commands are worth discussing, even though they may not be among the most useful emacs-mode commands.

[CTRL-O] is useful for repeating a sequence of commands you have already entered. Just go back to the first command in the sequence and press [CTRL-O] instead of RETURN. This will execute the command and bring up the next command in the history file. Press [CTRL-O] again to enter this command and bring up the next one. Repeat this until you see the last command in the sequence; then just hit RETURN.

[CTRL-U] , if it doesn't perform the line-delete function of your system's terminal interface, repeats the next command four times. If you type [CTRL-U] twice, the repeat factor becomes 16; for 3 [CTRL-U] s it's 64; and so on. [CTRL-U] is possibly most useful when navigating through your history file. If you want to recall a command that you entered a while ago, you could type [CTRL-U] [CTRL-P] to go back through the history file four lines at a time; you could think of this as a "fast rewind" through your command history.

Another possible use of [CTRL-U] is when you want to go from one end of a long pathname to the other. Unlike vi-mode, emacs-mode does not have a concept of "word" that is flexible enough to distinguish between pathnames and filename components. The emacs-mode word motion commands (ESC b and ESC f) will move through a pathname only one component at a time, because emacs-mode treats the slash as a word separator. You can use [CTRL-U] to help get around this limitation. If you have a line that looks like this:

$ ls -l /a/very/long/pathname/filename 

and you need to go back and change "very" to "really" you can type [CTRL-U] ESC b and your cursor will end up here:

$ ls -l /a/v
ery/long/pathname/filename

Then you can make the change:

$ ls -l /a/really/
long/pathname/filename

Judicious use of [CTRL-U] can save you a few keystrokes, but considering the small amount of information you manipulate when you edit command lines, it's probably not an incredibly vital feature. Often, holding down a key to repeat it is just as effective as [CTRL-U] . Because you'll probably have to redefine the terminal driver's line erase key before you can use [CTRL-U] , it's probably better to do without [CTRL-U] .

The mark mentioned in the explanation of [CTRL-W] should be familiar to emacs editor users, but its function in emacs-mode is a subset of that in the full editor. Emacs-mode keeps track of the place at which the last delete was performed (whether a delete character, word, line, or whatever); this place is called the mark . If nothing has been deleted on the current line, mark defaults to the beginning of the line. You can also set the mark to where your cursor is by typing ESC SPACE. [CTRL-X] [CTRL-X] ([CTRL-X] hit twice) causes the Korn shell to swap point and mark, i.e., to move your cursor to where the mark is and reset mark to where your cursor was before you typed [CTRL-X] [CTRL-X] .

The mark concept is not extremely useful because of the small amount of "distance" to travel in command lines. But if you ever have to make a series of changes in the same place in a line, [CTRL-X] [CTRL-X] will take you back there. In the previous example, if you wanted to change "really" to "monumentally", one way would be to type [CTRL-X] [CTRL-X] to return to the beginning of "really":

$ ls -l /a/r
eally/long/pathname/filename

Then you could type ESC d to delete "really" and make the change. Of course, you could do this faster by typing ESC DEL instead of [CTRL-X] [CTRL-X] and ESC d.

Of the case-changing commands, ESC l is useful when you hit the CAPS LOCK key by accident and don't notice it immediately. Since all-caps words aren't used too often in the UNIX world, you may not use ESC c very often.

If it seems like there are too many synonyms for RETURN, bear in mind that [CTRL-M] is actually the same (ASCII) character as RETURN, and that [CTRL-J] is actually the same as LINEFEED, which UNIX usually accepts in lieu of RETURN anyway.

ESC . and ESC _ are useful if you want to run several commands on a given file. The usual UNIX convention is that a filename is the last argument to a command. Therefore you can save typing by just entering each command followed by SPACE and then typing ESC . or ESC _. For example, say you want to examine a file using more , so you type:

$ more myfilewithaverylongname

Then you decide you want to print it, so you type the print command lp . You can avoid typing the very long name by typing lp followed by a space and then ESC . or ESC _; the Korn shell will insert myfilewithaverylongname for you.

2.3.7 Keyboard Shortcuts with Aliases

Finally, emacs-mode has an interesting way of defining keyboard shortcuts for commonly used commands by interacting with the Korn shell's alias facility, as described in the next chapter. Here's how it works: if you define an alias called _x , where x is a letter, then emacs-mode will expand the alias when you hit ESC x . The expansion will appear on your screen, but the Korn shell will not run the command, leaving you free to type more or just hit RETURN to run it. We don't find this particularly useful, since you can just define an alias in the normal way instead.


Previous: 2.2 The History File Learning the Korn Shell Next: 2.4 Vi Editing Mode
2.2 The History File Book Index 2.4 Vi Editing Mode

The UNIX CD Bookshelf NavigationThe UNIX CD BookshelfUNIX Power ToolsUNIX in a NutshellLearning the vi Editorsed & awkLearning the Korn ShellLearning the UNIX Operating System