It’s always possible to make mistakes when you type at a computer keyboard, but perhaps even more so when you are using a Unix shell. Unix shell syntax is powerful, yet terse, full of odd characters, and not particularly mnemonic, making it possible to construct command lines that are as cryptic as they are complex. The Bourne and C shells exacerbate this situation by giving you extremely limited ways of editing your command lines.
In particular, there is no way to recall a previous command line so that you can fix a mistake. For example, in Chapter 7 we’ll see complex command lines like:
eval cat \$srcname \| ccom \| optimize \| as \> \$objname
If you are an experienced Bourne shell user, undoubtedly you know the frustration of having to retype lines like this. You can use the backspace key to edit, but once you hit ENTER, it’s gone forever!
The C shell provides a small improvement via its history mechanism, which provides a few very awkward ways of editing previous commands. But there are more than a few people who have wondered, “Why can’t I edit my Unix command lines in the same way I can edit text with an editor?”
This is exactly what the Korn shell allows you to do. It has editing modes that allow you to edit command lines with editing commands similar to those of the two most popular Unix editors, vi and Emacs.[18] It also provides a much-extended analogue to the C shell history mechanism called hist (for “history”) that, among other things, allows you to use your favorite editor directly for editing your command lines.
In this chapter, we discuss features common to all of the Korn shell’s command-history facilities; then we deal with each such facility in detail. If you use vi or Emacs, you may wish to read only the section on the emulation mode for the one you use.[19] If you use neither vi or Emacs but are interested in learning one of the editing modes anyway, we suggest emacs-mode, because it is more of a natural extension of the minimal editing capability you get with the bare shell.
We should mention up front that both emacs- and vi-modes introduce the potential for clashes with control keys set up by the Unix terminal interface. Recall the control keys shown in Chapter 1 in Table 1-7 and the sample stty command output. The control keys shown there override their functions in the editing modes.
During the rest of this chapter, we warn you when an editing command clashes with the default setting of a terminal-interface control key. But if you (or your system administrator) choose to customize your terminal interface, as we show in Chapter 8, you’re on your own as far as the editing modes are concerned.
There are two ways of entering either editing mode.
First, you can set your editing mode by using the environment variable
VISUAL
. The Korn shell checks to see if this variable ends with
vi
or macs
.[20]
An excellent way to set VISUAL
is to put a line like the following in your .profile or environment file:
VISUAL=$(whence emacs)
or
VISUAL=$(whence vi)
As you will find out in Chapter 3 and Chapter 4,
the whence
built-in command takes the name of another command as its argument and
writes the command’s full pathname on
the standard output; the form $(
command
)
returns the standard output generated by command as a
string value. Thus, the line above finds out
the full pathname of your favorite editor and stores it in the
environment variable VISUAL
. The advantage of
this code is that it is portable to other systems, which may have
the executables for editors stored in different directories.
The second way of selecting an editing mode is to set the option explicitly with the set -o command:
set -o emacs
or
set -o vi
vi users may wish to add:
set -o viraw
along with set -o vi
. This enables TAB completion
in recent versions of ksh93.
The additional overhead, particularly on single-user systems, is nominal
and, in any case, is no worse than that of emacs-mode.
(Starting with ksh93n, the viraw
option is automatically enabled when you use vi-mode.)
You will find that the vi and emacs editing modes are good at emulating the basic commands of these editors, but not advanced features; their main purpose is to let you transfer “finger habits” from your favorite editor to the shell. hist is a powerful facility; it is mainly meant to supplant C shell history and as an “escape hatch” for users of editors other than vi or Emacs. Therefore the section on hist is recommended mostly to C shell users and those who don’t use either standard editor.
Before diving into the details, it’s worth mentioning two other points that apply to both editing modes:
ksh
indicates that a line is wider than your screen
by marking the last column of the visible line with a
special character: <
indicates that there is more
text on the left side of what you currently see, >
indicates there is more text to the right of what you see, and
*
indicates there is text on both sides of
what is currently visible.
$ print this is a very long line that just runs on and
>
Customization of the ksh93 editing modes is possible but requires knowledge of advanced features we haven’t covered yet. See Chapter 10 for the details.[21]
All of the Korn shell’s command history facilities depend on a file
that stores commands as you type them in. This file is
normally .sh_history in your home directory,
but you can call it whatever you like by setting the
environment variable HISTFILE
(see Chapter 3).
When you run one of the Korn shell’s editing modes, you are actually
running a mini-editor on your history file.
If you run more than one login session at a time (e.g., more than one xterm on an X Windows workstation), you may find it advantageous to maintain a separate history file for each login session. Put the following line in your .profile:
HISTFILE=~/.hist.$(tty | sed 's;.*/;;')
This creates a history file whose name ends with the last component of your terminal’s device name. For example, your window’s terminal device name might be /dev/pts/42. The sed command strips everything through the last slash, leaving just the 42. The history file then becomes ~/.hist.42. You can remove the history file at logout, as explained in Chapter 4. Or you can leave the files around, and your history will be there the next time you start a window on that same terminal device. (Preserving history between sessions is the point of the history file, after all.)
An attractive alternative is to use a single history file for all your windows. Each running instance of the Korn shell is smart enough to share its file with other running instances; from a second window, you can recall and edit the commands run in the first window.
Another environment variable, HISTSIZE
, can be used to determine
the maximum number of commands accessible from the history file. The
default is 128 (i.e., the 128 most recent commands),
which should be more than adequate.
If you are an Emacs user, you will find it most useful to think of emacs editing mode as a simplified Emacs with a single, one-line window. All of the basic commands are available for cursor motion, cut and paste, and search.
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.
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 |
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.
Unfortunately, emacs-mode doesn’t use the arrow keys,[22] 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 the heavy-duty customization that the full Emacs needs. Just about the only hardware requirements of emacs-mode are that the SPACE character overwrite the character on top of which it is typed, and that BACKSPACE moves to the left without overwriting the current character.
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 ENTER, 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 ENTER 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.[23]
If you make multiple deletes in sequence, CTRL-Y brings back everything that you’ve deleted. Its memory goes back to the last keystroke that wasn’t a delete; the deletes don’t have to be of the same type. For example, if you type DEL SPACE DEL SPACE CTRL-D CTRL-K, typing CTRL-Y retrieves the result of the last three operations but not the first delete.
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 on single characters; emacs-mode defines a word to be a sequence of one or more alphanumeric characters or underscores. (For the rest of this discussion, it will help to think of the underscore as a letter, even though it really isn’t.)
The word commands are shown in Table 2-2. Whereas the basic commands are all single characters, the word commands 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.
Command | Description |
ESC b | Move one word backward |
ESC f | Move one word forward |
ESC DEL, ESC h, ESC CTRL-H | Delete one word backward |
ESC d | Delete one word forward |
To return to our example: if we type ESC b, point moves back
a word. Since /
is not an alphanumeric character,
emacs-mode stops there:
$grep -l Bob < ~pete/wk/
names
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’s
argument 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 < ~
pete/wk/names
If we type ESC b again, we end up at the beginning of Bob:
$grep -l
Bob < ~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 a word was the last thing deleted.
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.
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, whether that was from a single delete command or several delete commands in a row. If you use CTRL-K, that could be quite a few characters.
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.
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 ENTER 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-Fs, and CTRL-D, you have:
$grep -
Dave < ~pete/wk/names
You decide to try -s instead of -l,
so you type s
and hit ENTER.
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 disappears
and is replaced by ^R
. Then type fgrep
, and you see this:
$ ^Rfgrep
Hit ENTER, and the shell searches backwards through the history file for a line containing “fgrep”. If it doesn’t find one, it beeps. But if it finds one, it displays 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 ENTER) causes the shell to repeat your last backward search. If you try the fgrep command by hitting ENTER again, two things happen. First, of course, the command runs. Second, the executed command line is 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-P and CTRL-R are clearly the most important emacs-mode commands that deal with the history file, and you might use CTRL-N occasionally. The others are less useful, and we suspect that they were included mainly 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 matches only commands that have the search string at the beginning of the line.
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 TAB. (Emacs users will find this familiar; it is the same as minibuffer completion with the TAB key.) When you type in a word of text followed by TAB, the Korn shell attempts to complete the name of a file in the current directory. Then one of four things can happen:
If there is no file whose name begins with the word, the shell beeps and nothing further happens.
If there is exactly one way to complete the filename, and the file is a regular file, the shell types the rest of the filename and follows it with a space so you can type in more command arguments.
If there is exactly one way to complete the filename, and the file is a directory, the shell completes the filename and follows it with a slash.
If there is more than one way to complete the filename, the shell completes 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 TAB. This is an ambiguous 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 TAB 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 previous
example, if you type ESC *
instead of TAB,
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.
Starting with ksh93m, the ESC = command accepts a numeric prefix. When a prefix is provided, the shell treats it as the number of one of the commands shown by a previous ESC = listing and completes the filename. (An example is provided later in this chapter where the vi-mode version of this command is described.)
When TAB, ESC *
, and ESC =
are used on the first
word of the command line, they expand aliases, functions, and commands.
This very useful feature is known as command completion.
For backwards compatibility with ksh88 and versions of ksh93 prior to ksh93h, you may instead type ESC ESC for filename and command completion.
Starting with ksh93l,
the editing modes understand ksh quoting rules;
expansions are ignored inside quotes. However,
if you have typed a leading quote but no closing quote yet, the completion
commands do work.
In addition, all three expansions work on variable names as well.
(Variables are discussed in Chapter 4.)
When ksh sees either a $
or
"$
and part of a variable name, you may use any of the
three expansions to see which variable names match what you’ve typed.
Several miscellaneous commands complete emacs editing mode; they are shown in Table 2-5.
Command | Description |
CTRL-J | Same as ENTER. |
CTRL-L | Redisplay the line. |
CTRL-M | Same as ENTER. |
CTRL-O | Same as ENTER, then display next line in history file. |
CTRL-T |
Transpose the characters on either side of point. This is like GNU Emacs.[a] |
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-E |
Invoke an editor — usually the emacs program — on the current command. |
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. |
CTRL-@ | Set mark at point. |
ESC c | 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 previous entry. |
ESC CTRL-] x | Search backward for x, where x is any character. |
ESC SPACE | Set mark at point. |
ESC # |
Prepend |
[a]
This is a difference from ksh88,
which transposes two characters to the right of point and moves point forward
by one.
CTRL-T behaves slightly
differently if you put |
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. Modern Unix 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. However, emacs-mode works by directly interpreting every character you type, so the stty settings are largely ignored.
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 ENTER. This executes the command and brings 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 ENTER.
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-Us 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) 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/
very/long/pathname/filename
Then you can make the change. First, get rid of “very” by typing CTRL-U CTRL-D:
$ls -l /a/
/long/pathname/filename
Then insert the new text:
$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 use the stty command to redefine the terminal driver’s line erase key before you can use CTRL-U, it’s probably better to do without it.
The mark mentioned in the explanation of CTRL-W should be familiar to Emacs 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 operation was performed (whether it was a character, word, line, or whatever); this place is called the mark. If nothing has been deleted on the current line, the mark defaults to the beginning of the line. You can also set the mark to where your cursor is by typing ESC SPACE (or, alternatively, CTRL-@). 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/
really/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 (letter ell) 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 ENTER, bear in mind that CTRL-M is actually the same (ASCII) character as ENTER, and that CTRL-J is actually the same as newline, which Unix usually accepts in lieu of ENTER 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, using 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
inserts myfilewithaverylongname for you.
If you’re a real Emacs expert and the built-in mode just isn’t working for you, use CTRL-X CTRL-E to invoke the emacs editor program on your command line. When you exit the editor, if you actually made changes to the file, the shell executes the final command line.
As you become accustomed to using emacs-mode, you may find that there are sequences of commands that you execute over and over again. Typing these commands repeatedly is difficult and time-wasting. It is better to define a macro for them. A macro is a short name that, when entered, expands into the full sequence of commands.
The Korn shell provides a macro facility, using the alias mechanism (described in the next chapter), that lets you set up a sequence of commands and then invoke that sequence with a single emacs-mode command. It works as follows: if you define an alias named _x, where x is a letter, then when you type ESC x, emacs-mode expands the alias, and reads it as input. The alias value may contain regular text, emacs-mode commands, or both.
For example, suppose that you want a command to capitalize the first letter of the current word. You could define an alias as follows:
alias _C='^[b^C' Value is ESC b CTRL-C
Now, whenever you type ESC C, the shell moves to the beginning of the current word (ESC b), and then capitalizes the current letter (CTRL-C).
$print here is a word
Type ESC C $print here is a W
ord
Like emacs-mode, vi-mode essentially creates a one-line editing window into the history file. Vi-mode is popular because vi is the most standard Unix editor. But the function for which vi was designed, writing C programs, has different editing requirements from those of command interpreters. As a result, although it is possible to do complex things in vi with relatively few keystrokes, the relatively simple things you need to do in the Korn shell sometimes take too many keystrokes.
Like vi, vi-mode has two modes of its own: input and control mode. The former is for typing commands (as in normal Korn shell use); the latter is for moving around the command line and the history file. When you are in input mode, you can type commands and hit ENTER to run them. In addition, you have minimal editing capabilities via control characters, which are summarized in Table 2-6.
Command | Description |
DEL | Delete previous character |
CTRL-W | Erase previous word (i.e., erase until whitespace) |
CTRL-V | “Quote” the next character |
ESC | Enter control mode (see below) |
At least some of these editig commands — depending on which version of Unix you have — are the same as those provided by modern Unix systems in the terminal interface. Vi-mode uses your “erase” character as the “delete previous character” key; usually it is set to DEL or CTRL-H (BACKSPACE). CTRL-V causes the next character you type to appear in the command line as is; i.e., if it is an editing command (or an otherwise special character like CTRL-D), it is stripped of its special meaning.
Under normal circumstances, you just stay in input mode. But if you want to go back and make changes to your command line, or if you want to recall previous commands, you need to go into control mode. To do this, hit ESC.
A full range of vi editing commands are available to you in control mode. The simplest of these move you around the command line[24] and are summarized in Table 2-7. Vi-mode contains two “word” concepts. The simplest is any sequence of non-whitespace characters; we’ll call this a nonblank word. The other is any sequence of only alphanumeric characters (letters and digits) or any sequence of only non-alphanumeric characters; we’ll just call this a word.[25]
Command | Description |
h
| Move left one character. |
l
| Move right one character. |
space | Move right one character. |
w
| Move right one word. |
b
| Move left one word. |
W
| Move to beginning of next nonblank word. |
B
| Move to beginning of preceding nonblank word. |
e
| Move to end of current word. |
E
| Move to end of current nonblank word. |
0
| Move to beginning of line. |
^
| Move to first nonblank character in line. |
$
| Move to end of line. |
All of these commands except the last three can be preceded by a number that acts as a repeat count. The last two will be familiar to users of Unix utilities (such as grep) that use regular expressions, as well as to vi users.
Time for a few examples. Let’s say you type in this line and, before you hit ENTER, decide you want to change it:
$ fgrep -l Bob < ~pete/wk/names
As shown, your cursor is beyond the last character of the line.
First, type ESC to enter control mode; your cursor moves
back one space so that it is on the s
. Then if you type h
, your
cursor moves back to the e
. If you type 3h
from
the e
,
you end up at the n
.
Now we look at the difference between the two “word” concepts.
Go back to the end of the line by typing $
.
If you type b
, the word in question is “names”, and the cursor
ends up on the n
:
$fgrep -l Bob < ~pete/wk/
names
If you type b
again, the next word is the slash (it’s a “sequence”
of non-alphanumeric characters), so the cursor ends up over it:
$fgrep -l Bob < ~pete/wk
/names
However, if you typed B
instead of b
,
the nonblank word
would be the entire pathname, and the cursor ends up at
the beginning of it — that is, over the tilde:
$fgrep -l Bob <
~pete/wk/names
You would have had to type b
four times — or
just 4b
— to
get the same effect, since there are four “words” in the
part of the pathname to the left of /names:
wk, slash, pete, and the leading tilde.
At this point, w
and W
do the opposite: typing w
gets you over the
p
, since the tilde is a “word,” while typing
W
brings you to the end of the line. But whereas
w
and W
take you to the beginning
of the next word, e
and E
take you
to the end of the current word. Thus, if you type w
with the cursor on the tilde, you get to:
$fgrep -l Bob < ~
pete/wk/names
Then typing e
gets you to:
$fgrep -l Bob < ~pet
e/wk/names
And typing an additional w
gets you to:
$fgrep -l Bob < ~pete
/wk/names
On the other hand, E
gets you to the end of the current
nonblank word — in this case, the end of the line.
(While at first glance the commands may appear non-mnemonic, there is
generally some order to the choice of command letters.
Each command letter is usually the first letter of the English word for the operation.
Lowercase letters work on words, while the uppercase versions work on
nonblank words. Getting the hang of this is undoubtedly tougher if
English isn’t your native language, but that also applies to the
emacs-mode commands.)
Now that you know how to enter control mode and move around on the command line, you need to know how to get back into input mode so you can make changes and type in additional commands. A number of commands take you from control mode into input mode; they are listed in Table 2-8. All of them enter input mode a bit differently.
Command | Description |
i
| Text inserted before current character (insert) |
a
| Text inserted after current character (append) |
I
| Text inserted at beginning of line |
A
| Text inserted at end of line |
r
| Replace one character (doesn’t enter input mode) |
R
| Text overwrites existing text (replace) |
Most likely, you will use either i
or
a
consistently, and you may use R
occasionally. I
and A
are
abbreviations for 0i
and $a
respectively. To illustrate the difference between i
,
a
, and R
, say we start out with
our example line:
$fgrep -l Bob < ~pete/wk
/names
If you type i
followed by end
, you get:
$fgrep -l Bob < ~pete/wkend
/names
That is, the cursor always appears to be over the /
before names.
But if you type a
instead of i
,
you will notice the cursor move one space to
the right. Then if you type nick
, you get:
$fgrep -l Bob < ~pete/wk/nick
names
That is, the cursor is always just after the last character you
typed, until you type ESC to end your input.
Finally, if you go back to the n
in names,
type R
instead, and then type task
, you will see:
$ fgrep -l Bob < ~pete/wk/task
s
In other words, you will be replacing (hence R
) instead
of inserting text.
Why capital R
instead of lowercase r
? The latter is a slightly
different command, which replaces only one character and does not
enter input mode. With r
, the next single character overwrites the
character under the cursor. So
if we start with the original
command line and type r
followed by a semicolon, we get:
$fgrep -l Bob < ~pete/wk
;names
If you precede r
with a number N,
it allows you to replace
the next N existing characters on the line — but
still not enter input mode.
Vi-mode replaces the N characters on the line with
N copies of the character you type after
the r
.
Lowercase r
is effective for fixing erroneous option letters,
I/O redirection characters, punctuation, etc.
Now that you know how to enter commands and move around the
line, you need to know how to delete.
The basic deletion command in vi-mode is d
followed by one
other letter. This letter determines what the unit and direction
of deletion is, and it corresponds to a motion command, as
listed previously in
Table 2-7.
Table 2-9
shows some
commonly used examples.
Command | Description |
dh
| Delete one character backwards. |
dl
| Delete one character forwards. |
db
| Delete one word backwards. |
dw
| Delete one word forwards. |
dB
| Delete one nonblank word backwards. |
dW
| Delete one nonblank word forwards. |
d$
| Delete to end of line. |
d0
| Delete to beginning of line. |
These commands have a few variations and abbreviations.
If you use a c
instead of d
, you enter input mode
after it does the deletion. You can supply a numeric
repeat count
either before or after the d
(or c
).
Table 2-10
lists the available abbreviations.
Most people tend to use D
to delete to end of line,
dd
to delete an entire line, and x
(as “backspace”)
to delete single characters. If you aren’t a hardcore vi
user, you may find it difficult to get some of the more
esoteric deletion commands under your fingers.
Command | Description |
D
| Equivalent to d$ (delete to end of line) |
dd
| Equivalent to 0d$ (delete entire line) |
C
| Equivalent to c$ (delete to end of line, enter input mode) |
cc
| Equivalent to 0c$ (delete entire line, enter input mode) |
s
| Equivalent to xi (delete current character, enter input mode) |
S
| Equivalent to cc (delete entire line, enter input mode) |
x
| Equivalent to dl (delete character forwards) |
X
| Equivalent to dh (delete character backwards) |
Every good editor provides “undelete” commands as well as
delete commands, and vi-mode is no exception. Vi-mode maintains
a delete buffer that stores all of the modifications to
text on the current line only (note that this is different
from the full vi editor). The command u
undoes the last
text modification command only, while U
undoes all such
commands on the current line. So if you make one change and
want to undo it, type u
; if you make lots of changes and find
that the original is closer to what you want, you can undo everything
by typing U
. A related command is .
(dot), which redoes the
last text modification command.
There is also a way to save text in the delete buffer without having
deleted it in the first place: just type in a delete command but use
y
(“yank”) instead of d
. This
does not modify anything, but it allows you to retrieve the yanked text
as many times as you like later on. The command to retrieve yanked
text is p
, which inserts (“puts”) the text on the
current line to the right of the cursor.
The uppercase version, P
, puts text to the left of
the cursor.
The various cut and paste commands are summarized in
Table 2-11.
Command | Description |
y
|
Yank (save) text, don’t actually change the line. |
p
|
Put the last yanked or deleted text into the line after the cursor. |
P
|
Put the last yanked or deleted text into the line before the cursor. |
u
|
Undo most recent change. |
U
|
Undo all changes to the line. |
. (dot) |
Redo last change at current cursor position. |
The d
and p
commands are quite
useful together for rearranging the order of options or arguments on
a command line.
As an example, most Unix C compilers accept a -l option
that indicates the name of a library to use when linking a compiled program.
The -L option specifies a directory in which
the compiler should look for libraries, besides looking in the standard
places for system libraries.
cc -o myprog myprog.c -Lmylibdir -lmylib
This command looks for the library file libmylib.a in the
directory mylibdir when compiling and linking myprog.c.
So far so good. The catch is that typically the -L option must appear
on the command line before the -l option.
Let’s suppose you accidentally typed them the other way around, and therefore that the
compilation failed. You can use the d
and p
commands to rearrange things. Start by recalling the line:
$ c
c -o myprog myprog.c -lmylib -Lmylibdir
Next, move to the last option with 5w
.
Then back up to the preceding space with h
.
Your command line now looks like this:
$cc -o myprog myprog.c -lmylib
-Lmylibdir
Type D
to delete the rest of the line:
$ cc -o myprog myprog.c -lmyli
b
Now move back to the preceding c
character with Bhh
:
$cc -o myprog myprog.
c-lmylib
Finally, use p
to insert the moved option:
$cc -o myprog myprog.c -Lmylibdi
r-lmylib
Then hit ENTER and you’re done. This looks like a lot of typing. But, as we will soon see, there are additional commands that let you search for characters on the command line, making it much easier to move around. And if you’re an experienced vi user, you’ll be right at home.
The next group of vi control mode commands we cover allows you to move around in and search your history file. This is the all-important functionality that lets you go back and fix an erroneous command without retyping the entire line. These commands are summarized in Table 2-12.
Command | Description |
k or -
| Move backward one line. |
j or +
| Move forward one line. |
G
|
Move to line given by repeat count, or to very first history line if no repeat count. |
?
string
| Search backward for string. |
/
string
| Search forward for string. |
n
| Repeat search in same direction as previous. |
N
| Repeat search in opposite direction of previous. |
The first three can be preceded by repeat counts
(e.g., 3k
or 3-
moves back three lines in the history file).
If you aren’t familiar with vi and its cultural history, you
may be wondering at the wisdom of choosing such seemingly
poor mnemonics as h
, j
, k
, and l
for backward character, forward line,
backward line, and forward character, respectively. Well, there
actually is a rationale for the choices — other than that they
are all together on the standard keyboard.
Bill Joy originally developed vi to run on Lear-Siegler ADM-3a terminals,
which were the first popular models with addressable cursors
(meaning that a program could send a command to an ADM-3a
to make it move the cursor to a specified location on the screen).
The ADM-3a’s h
, j
, k
, and l
keys
had little arrows on them, so Joy
decided to use those keys for appropriate commands in vi.
Another (partial) rationale for the command choices is that CTRL-H is the traditional backspace key, and CTRL-J denotes linefeed. The primary rationale for these choices, however, is that with these keys, it’s never necessary to move your hands off the “home row” of the keyboard.
Perhaps +
and -
are better mnemonics
than j
and k
, but the latter
have the advantage of being more easily accessible to touch
typists. In either case, these commands are the most basic ones
for moving around the history file. To see how they work,
let’s take the same examples we used when discussing emacs-mode
earlier.
You enter the example command (ENTER works in both input and control modes, as does newline or CTRL-J):
$ fgrep -l Bob < ~pete/wk/names
But you get an error message saying that your
option letter was wrong. You want to change it to -s without having
to retype the entire command. Assuming you are in control
mode (you may have to type ESC to put yourself in control mode), you
type k
or -
to get the command back. Your cursor
will be at the beginning of the line:
$ f
grep -l Bob < ~pete/wk/names
Type w
to get to the -
, then l
or space
to get to the l
. Now you can replace
it by typing rs
; press ENTER to run the command.
Now let’s say you get another error message, and you finally decide
to look at the manual page for the fgrep command. You remember having
done this a while ago today, so rather than typing in the entire
man(1) command, you search for the last one you used. To do this, type ESC to enter control mode (if you are already in control mode, this has no effect), then type /
followed
by man
or ma
. To be on the safe side, you can also type
^ma
; the ^
means match only lines
that begin with ma
.[26]
But typing /^ma
doesn’t give you what you want; instead, the shell
gives you:
$ m
ake myprogram
To search for “man” again, you can type n
, which does another backward
search using the last search string. Typing /
again without an
argument and hitting ENTER accomplishes the same thing.
The G
command retrieves the command whose number is
the same as the numeric prefix argument you supply. G
depends on the
command numbering scheme described
in Section 3.4.2.3,
in Chapter 3.
Without a prefix argument,
it goes to command number 1. This may be useful to former C shell users
who still want to use command numbers.
There are some additional motion commands in vi-mode. These commands allow you to move to the position of a particular character in the line. They are summarized in Table 2-13, in which x denotes any character.
All of these commands can be preceded by a repeat count.
Command | Description |
f
x
| Move right to next occurrence of x (find). |
F
x
| Move left to previous occurrence of x (find backwards). |
t
x
|
Move right to next occurrence of x, then back one position (go to the character). |
T
x
|
Move left to previous occurrence of x, then forward one position (go backwards to the character). |
;
| Redo last character-finding command. |
,
| Redo last character-finding command in opposite direction. |
%
|
Move to matching
|
Starting with the previous example: let’s say you want to change
Bob to Rob. Make sure that you’re at the end of the line (or, in
any case, to the right of the B
in Bob);
then, if you type FB
, your
cursor moves to the B
:
$fgrep -l
Bob < ~pete/wk/names
At this point, you could type rR
to replace
the B
with R
.
But let’s say you wanted to change Bob to Blob. You would
need to move one space to the right of the B
. Of course, you
could just type l
. But, given that you’re somewhere to the right of
Bob, the fastest way to move to the o
would be to type
TB
instead of FB
followed by l
.
As an example of how the repeat count can be used with
character-finding commands, let’s say you want to change the filename from
names to namfile.
In this case, assuming your cursor is still on the B
, you need to get
to the third e
to the right, so you can type 3te
, followed by
l
to put the cursor back on the e
in names.
The character-finding commands also have associated delete commands.
Read the command definitions in the previous table and mentally
substitute “delete” for “move.” You’ll get what happens when you
precede the given character-finding command with a d
. The deletion
includes the character given as argument.
For example, assume that your cursor is under the n
in names:
$fgrep -l Bob < ~pete/wk/
names
If you want to change names to aides,
one possibility is to type dfm
.
This means “delete right to next occurrence of m,” i.e., delete “nam.”
Then you can type i
(to enter input mode) and then “aid” to complete
the change.
A better way, though, is to use cfm
.
This means “change everything from under the cursor up to and including the next
occurrence of m.” This deletes “nam” and enters input mode for you.
The %
command is very useful for finding the matching “pair”
character when used with parentheses, square brackets, and curly braces.
All of these occur frequently in matched pairs on shell command lines.
One final command rounds out the vi control mode commands
for getting around on the current line: you can use the pipe character
(|
) for moving to a specific column, whose number is given by
a numeric prefix argument. Column counts start at 1;
count only your input, not the space taken up by the prompt string.
The default repeat count is 1, of course, which
means that typing |
by itself is equivalent to 0
(see Table 2-7).
Vi-mode provides one additional feature that we think you will use quite often: filename completion. This feature is not part of the real vi editor, and it was undoubtedly inspired by similar features in Emacs and, originally, in the TOPS-20 operating system for DEC mainframes.
The rationale behind filename completion is simple: you should
have to type only as much of a filename as is necessary to
distinguish
it from other filenames in the same directory. Backslash
(\
) is
the command that tells the Korn shell to do filename completion in vi-mode.
If you type in a word, type ESC to enter control mode,
and then type \
, one of four things happens; they are
the same as for TAB (or ESC ESC) in emacs-mode:
If there is no file whose name begins with the word, the shell beeps and nothing further happens.
If there is exactly one way to complete the filename, and the file is a regular file, the shell types the rest of the filename, followed by a space in case you want to type in more command arguments.
If there is exactly one way to complete the filename, and the file is a directory, the shell completes the filename, followed by a slash.
If there is more than one way to complete the filename, the shell completes out to the longest common prefix among the available choices.
As in emacs-mode, starting with ksh93h, you may use TAB instead of ESC \. However, this only works if you use set -o viraw in addition to set -o vi. (The viraw option is a bit more CPU-intensive — although probably not noticeably — and is required on some older Unix systems for vi-mode to work at all.) Fortunately, beginning with ksh93n, the viraw option is automatically enabled when you use vi-mode.
A related command is *
, which is the same as ESC *
in emacs-mode
as described earlier in this chapter.[27]
It behaves similarly to ESC \
, but
if there is more than one completion possibility (number four in the list
above), it lists all of them and allows you to type further.
Thus, it resembles the *
shell wildcard character.
Finally,
the command =
does the same kind of filename
expansion as the *
shell wildcard, but in a different way.
Instead of expanding the filenames onto the command line,
it prints them in a numbered list with one filename on each line.
Then it gives you your shell prompt back and retypes whatever was
on your command line before you typed =
.
For example, if the files in your directory include program.c
and problem.c,
and you type pro
followed by ESC and then =
, you will see this:
$cc pro
ESC = typed at this point 1) problem.c 2) program.c $cc pr
o
Beginning with ksh93m, prefixing the = command with a count indicates selection of a particular option. Returning to the previous example: after listing both problem.c and program.c, the command line looks like this:
$ cc pr
o
If you want program.c, it’s enough to type
2 =
, and the shell picks expansion number 2.
The command line changes to:
$ cc program.c
As in emacs-mode, you can also do command completion from vi-mode.
The *
, \
,
and =
commands, when used on the first
word of the command line, expand aliases, functions, and commands.
Also as in emacs-mode,
starting with ksh93l,
these expansions work when you’ve opened a quoted
string but haven’t closed it yet, and for variable expansions with
$
and "$
.
Several miscellaneous commands round out vi-mode; some of them are quite esoteric. They are listed in Table 2-14.
Command | Description |
~
| Invert (“twiddle”) case of current character(s). |
_
|
Append last word of previous command; enter input mode. A repeat count appends the given nth word, starting from the beginning of the command. |
v
|
Run the hist command on the current line
(actually, run the command |
CTRL-L |
Start a new line and redraw the current line on it; good for when your screen becomes garbled. |
CTRL-V | Print the version of the Korn shell. |
#
|
Prepend |
@
x
|
Insert expansion of alias _x as command mode input (see text). |
[a]
The line is also “executed” by the shell. However, |
The first of these can be preceded by a repeat count.
A repeat count of n preceding the ~
changes the case of
the next n characters.[28]
The cursor advances accordingly.
A repeat count preceding _ causes the nth word in the previous command to be inserted in the current line; without the count, the last word is used. Omitting the repeat count is useful because a filename is usually the last thing on a Unix command line, and because users often run several commands in a row on the same file. With this feature, you can type all of the commands (except the first) followed by ESC _, and the shell inserts the filename.
Just as described earlier for emacs-mode, you may use the shell’s
alias facility (described in the next chapter) to create macros,
i.e., single-letter abbreviations for longer sequences of commands.
If you create an alias named _x, where x
is a letter, then when you type @
x,
vi-mode expands the alias and reads it as command-mode input.
As before, suppose that you want a command to capitalize the first letter of the current word. You could define an alias as follows:
alias _C='B~'
Now, if you type ESC @ C, the cursor moves to the beginning of the current word (B), and then capitalizes the current letter (~).
$print here is a word
Type ESC @ C $print here is a W
ord
hist is a shell built-in command[29] that provides a superset of the C shell history mechanism. You can use it to examine the most recent commands you entered, to edit one or more commands with your favorite “real” editor, and to run old commands with changes without having to type the entire command in again. We’ll look at each of these uses.
The -l option for hist lists previous commands. It takes arguments that refer to commands in the history file. Arguments can be numbers or alphanumeric strings; numbers refer to the commands in the history file, while strings refer to the most recent command beginning with the string. hist treats arguments in a rather complex way:
If you give two arguments, they serve as the first and last commands to be shown.
If you specify one number argument, only the command with that number is shown.
With a single string argument, hist searches for the most recent command starting with that string and shows you everything from that command to the most recent command.
If you specify no arguments, you will see the last 16
commands you entered. Thus, hist -l
by itself is equivalent to the
C shell history command, and indeed the Korn shell defines a
built-in alias history as:
alias history='hist -l'
As you will find out in Chapter 3,
this means that you can type history
and the Korn shell will run the
command hist -l
.
A few examples should make these options clearer. Let’s say you logged in and entered these commands:
ls -l more myfile vi myfile wc -l myfile pr myfile | lp -h
If you type hist -l
(or history
)
with no arguments, you will see the above list with
command numbers, as in:
1 ls -l 2 more myfile 3 vi myfile 4 wc -l myfile 5 pr myfile | lp -h
The option -n suppresses the line numbers. If you want to see only
commands 2 through 4, type hist -l 2 4
. If you want to see only the
vi command, type hist -l 3
. To see everything from the
vi command up to the present, type hist -l v
. Finally,
if you want to see commands between more and wc,
you can type hist -l m w
,
hist -l m 4
, hist -l 2 4
, etc.
Negative history numbers indicate values relative to the current command number.
For example, hist -l -3
shows the 3rd previous command.
A less confusing way to to do this is with the -N option:
hist -l -N 3
does the same thing.
This also has the advantage of conforming to the POSIX conventions for options and
arguments.
The -l option to hist is not particularly useful, except as a quick way of remembering what commands you typed recently. Use the history alias if you are an experienced C shell user.
The other important option to hist is -e for “edit.” This is useful as an “escape hatch” from vi- and emacs-modes if you aren’t used to either of those editors. You can specify the pathname of your favorite editor and edit commands from your history file; then when you have made the changes, the shell actually executes the new lines.
Let’s say your favorite editor is a little home-brew gem called zed. You could edit your commands by typing:
$ hist -e /usr/local/bin/zed
This seems like a lot of work just to fix a typo in your
previous command; fortunately, there is a better way.
You can set the environment variable HISTEDIT
to the pathname of the
editor you want hist to use.
If you put a line in your .profile or environment file
saying:
HISTEDIT=/usr/local/bin/zed
you get zed when you invoke hist.
HISTEDIT
defaults to
the old line editor ed,
so that the overall default is also ed.[30]
hist is usually used to fix a recent command.
Therefore, it handles arguments a bit differently than it does
for the hist -l
variation above:
With no arguments, hist loads the editor with the most recent command.
With a numeric argument, hist loads the editor with the command with that number.
With a string argument, hist loads the most recent command starting with that string.
With two arguments to hist, the arguments specify the beginning and end of a range of commands, as above.
Remember that hist actually runs the command(s) after you
edit them. Therefore, the last-named choice can be dangerous.
The Korn shell attempts to execute all commands in the range
you specify
when you exit your editor. If you have typed in any multiline
constructs (like those we will cover in
Chapter 5),
the results could be even more dangerous.
Although these might seem like valid ways of generating
“instant shell programs,” a far better strategy would be to direct
the output of hist -nl
with the same arguments to a file;
then edit that file and execute the commands when you’re satisfied
with them:
$hist -nl cp > lastcommands
List all commands that start with cp into lastcommands $vi lastcommands
Edit lastcommands $. lastcommands
Run the commands in it
In this case, the shell will not try to execute the file when you leave the editor!
There is one final use for hist. If you specify the option -s
(i.e., type hist -s
), the Korn shell will skip the editing part
and just run the command(s) specified by the argument(s).
Why is this useful? For one thing, just typing hist -s
causes the previous command to repeat, just like the C shell
!!
command. The Korn shell provides the built-in alias r for this,
so that if you type r
and hit ENTER, you will repeat
the last command.
This form of hist allows yet another type of argument, of the
form old
=
new
,
meaning “change occurrences of old in the specified
previous command to new and then run it.”
(Unfortunately, you can’t get the Korn shell to make this kind of
substitution more than once; it only changes the first occurrence
of old to new.)
For example,
suppose that you are using troff and its preprocessors to work
on a document.[31]
If you accidentally ran the tbl preprocessor
with this command:
tbl ch2.tr | troff -ms -Tps > ch2.ps
but you needed to run eqn, you can redo it by typing
hist -s tbl=eqn
. (You could also
use the alias, r tbl=eqn
.) This command would then run:
eqn ch2.tr | troff -ms -Tps > ch2.ps
The Korn shell prints the modified command before running it.
To paraphrase the old adage, old finger habits die hard. In fact, that is the primary reason for the choices of vi and Emacs for the Korn shell’s editing modes. If you are an experienced user of one of these editors, by all means use the corresponding Korn shell editing mode. If you are a vi wizard, you probably know how to navigate between any two points on a line in three keystrokes or less.
But if you’re not, you should seriously consider adopting emacs-mode finger habits. Because it is based on control keys, just like the minimal editing support you may have already used with the Bourne or C shell, you will find emacs-mode easier to assimilate. Although the full Emacs is an extremely powerful editor, its command structure lends itself very well to small subsetting: there are several “mini-emacs” style editors floating around for Unix, MS-DOS, and other systems.
The same cannot be said for vi, because its command structure is really meant for use in a full-screen editor. vi is quite powerful too, in its way, but its power becomes evident only when it is used for purposes similar to that for which it was designed: editing source code in C and LISP. Doing complicated things in vi takes relatively few keystrokes. But doing simple things takes more keystrokes in vi-mode than it does in emacs-mode. Unfortunately, the ability to do simple things with a minimal number of keystrokes is most desired in a command interpreter, especially nowadays when users are spending more time within applications and less time working with the shell.
Both Korn shell editing modes have quite a few commands; you will undoubtedly develop finger habits that include just a few of them. If you use emacs-mode and you aren’t familiar with the full Emacs, here is a subset that is easy to learn yet enables you to do just about anything:
For cursor motion around a command line, stick to CTRL-A and CTRL-E for beginning and end of line, and CTRL-F and CTRL-B for moving around.
Delete using DEL (or whatever your “erase” key is) and CTRL-D; as with CTRL-F and CTRL-B, hold down to repeat if necessary. Use CTRL-C to erase the entire line.
Use CTRL-P to retrieve the last command when you make a mistake.
Use CTRL-R to search for a command you need to run again.
Definitely use TAB for filename, command, and variable completion.
After a few hours spent learning these finger habits, you will wonder how you ever got along without command-line editing.
[18] For some unknown reason, the documentation on emacs-mode has been removed from the ksh(1) manual pages on some Unix systems. This does not mean, however, that the mode doesn’t exist or doesn’t work properly.
[19] You will get the most out of these sections if you are already familiar with the editor(s) in question. Good sources for more complete information on the editors are Learning the vi Editor by Linda Lamb and Arnold Robbins and Learning GNU Emacs by Debra Cameron, Bill Rosenblatt, and Eric Raymond. Both are published by O’Reilly & Associates.
[20] GNU Emacs is sometimes installed as gmacs or gnumacs.
[21] The public domain Korn shell, bash, and zsh have editing modes that are customizable, but in a different way from ksh93. See Appendix A.
[22] In fact, as described in Appendix B, starting with ksh93h, if your terminal uses ANSI-standard escape sequences for the arrow keys, you can use them.
[23] Emacs users should note that this usage of CTRL-Y is different from the full editor, which doesn’t save character deletes.
[24] As with emacs mode, since ksh93h, you may use ANSI-standard arrow key sequences for moving back and forth on the command line, and up and down within the history list.
[25] Neither of these definitions is the same as the definition of a word in emacs-mode.
[26]
Fans of vi and search utilities like grep should note
that caret (^
) for beginning-of-line is the only context operator
vi-mode provides for search strings.
[27] If you count the ESC needed to get out of input mode, the vi-mode command is identical to emacs-mode.
[28]
This, in our opinion, is a design flaw in the vi editor
that the Korn shell authors might have corrected. Letting the user
append a motion command to ~
and having it behave analogously to d
or y
would have been much more useful; that way, a word
could be case-twiddled with only two keystrokes.
[29] In ksh88, this command is called fc, for “fix command.” ksh93 provides a built-in alias for fc to hist, for those who are used to using the fc command. Recent versions also have fc as a built-in command that behaves identically to hist; this is because POSIX requires that this command be built-in.
[30]
The default is actually a bit complicated in ksh93.
hist -e
runs ${HISTEDIT:-$FCEDIT}
to edit the command line.
This preserves compatibility with ksh88,
where the variable for the fc
command was, not surprisingly, FCEDIT
.
If neither variable is set, you get /bin/ed.
(The ${HISTEDIT:-$FCEDIT}
construct is explained in
Chapter 4. The upshot is to use the editor specified by
the HISTEDIT
variable if it’s set; otherwise use the value
of the FCEDIT
variable.)
[31] If so, you’re one of a rare breed!