by John Valley and Chris Johnson
Chapter 8, "What Is a Shell," introduced the basics of UNIX shells, and Chapter 9, "The Bourne Shell," discussed the Bourne shell in particular. This chapter expands on the subject of shells by introducing the Korn shell--the second of the three main shell languages available to you. The third major shell language is discussed in Chapter 12, "The C Shell."
The Korn shell is named after its author, David G. Korn of AT&T's Bell Laboratories, who wrote the first version of the program in 1986. Therefore, the Korn shell is a direct descendent of the Bourne shell. It is almost perfectly compatible with the Bourne shell; with a few minor exceptions, any shell script written to be executed by the Bourne shell can be executed correctly by the Korn shell. As a general rule, though, Korn shell scripts cannot be processed correctly by the Bourne shell.
This upward compatibility provides a number of advantages--not the least of which is that it enables you to capitalize on your knowledge of the Bourne shell immediately. It also drastically reduces the amount of material you need to learn to begin using the Korn shell.
Because the Korn shell is intended as a replacement for and an improvement on the Bourne shell, it is best discussed as a series of features added to the basic functionality of the Bourne shell. Many aspects of the shell's operation presented in Chapter 9, "The Bourne Shell," are not repeated here. Instead, this chapter summarizes the differences between the Bourne shell and the Korn shell.
The list of Korn shell enhancements is extensive, ranging from the profound to the trivial. The most dramatic enhancements are those intended to facilitate keyboard interaction with the shell, but you also should be aware of many important extensions to shell syntax and shell programming techniques. The categories of enhancements follow:
Although you haven't been introduced to the C shell yet, you'll find that many of the Korn shell features duplicate those of the C shell, but with a different syntax. This is intentional. Although the C shell offers many desirable features, its general syntax is incompatible with the Bourne shell, making it somewhat of a square peg in a round hole in the UNIX world. The Korn shell solves this long-standing quandary in the UNIX world by offering the keyboard and shell programming features that people want, but in a form that is compatible with the old, well-established Bourne shell standard.
As I mentioned earlier, the Korn shell is essentially a foundation equivalent to the Bourne shell with a new layer of goodies added on top. You can use the Korn shell as a one-for-one replacement of the Bourne shell, with no special knowledge of Korn shell features. Korn shell extensions do not come into play until you explicitly invoke them.
In particular, the Korn shell is identical to the Bourne shell in the following areas:
$ cat <<-! This is a demonstration of a here document. As you can see the docuemnt uses the operator << to tell the shell that all the text on the next line to the label, in this case is !, is all to be read in and redirected to the cat command. This - tells the shell to remove leading tabs at the start of the line. !
This is a demonstration of a here document. As you can see the docuemnt uses the operator << to tell the shell that all the text on the next line to the label, in this case is !, is all to be read in and redirected to the cat command. This - tells the shell to remove leading tabs at the start
The general philosophy of the Korn shell is to invoke extensions and special features with syntax that is not legal for the Bourne shell. As a result, any commands and shell scripts that are syntactically correct for the Bourne shell will be interpreted identically by the Korn shell. All Korn shell extensions use syntactic forms that do not appear in the Bourne shell language.
Features that are not invoked directly by commands, such as command history and command editing, are controlled instead by shell options. To use command editing, you first must issue the command set -o vi or set -o emacs. If you don't, the Korn shell command line works the same as the Bourne shell. Also note that the set command follows the general philosophy: set -o is not valid in the Bourne shell and generates a syntax error.
The compatibility between the Bourne shell and Korn shell is nearly perfect; one of the design objectives of the Korn shell was that it be able to execute system-provided shell scripts written for the Bourne shell without the need to revise those scripts or to invoke the Bourne shell to run them. This objective meant that even minor idiosyncrasies of Bourne shell behavior could not be overlooked; the Korn shell design had to implement them all.
The upshot of all this is that everything in Chapter 9 applies equally well, without restriction or caveat, to the Korn shell.
The Bourne shell supports a number of syntactic forms for abbreviating a command-line reference to filenames. These forms are based on the idea of embedding one or more special pattern-matching characters in a word. The word then becomes a template for filenames and is replaced by all the filenames that match the template. The pattern-matching characters supported by the Bourne shell are *, ?, and the bracketed expression [...].
These pattern-matching characters are supported by the Korn shell, as well as a tilde expansion that uses the ~ character to shorten pathnames and the extended pattern-matching expressions, *(), ?(), +(), @(), and !(). The syntax of pattern-matching expressions is based on the recognition of unquoted parentheses--()--in a word. Parentheses are special to the shell in both the Bourne and Korn shells; they must be quoted to avoid their special meaning. The Bourne shell attaches no special significance to a word such as here+(by|with), but it would complain about the parentheses. Thus, words containing embedded parentheses do not occur in the Bourne shell. The Korn shell therefore uses this syntax to extend wildcard pattern-matching without impairing Bourne shell compatibility.
Tilde Expansion A word beginning with ~ (the tilde) is treated specially by the Korn shell. To avoid its special meaning, you must quote the tilde. Note that words containing a tilde in any position except for the first are treated normally. The tilde has a special meaning only when it appears as the first character of a word.
Table 11.1 lists the four styles of tilde expansion.
|~||When used by itself or followed by a slash (/), the tilde is replaced by the pathname of your home directory. It is the same as writing $HOME or $HOME/....||$ echo
$ echo ~/bin
|~string||A tilde followed by an alphanumeric string is replaced by the home directory of the named user. It is an error if no entry exists in the /etc/passwd file for string.||$ echo ~bill
|~+||A tilde followed by a plus sign is replaced by the full pathname of the current directory. It is the same as writing $PWD or $PWD/....||$ pwd
$ echo ~+/bin
|~-||A tilde followed by a minus sign is replaced by the full pathname of the previous directory. It is the same as writing $OLDPWD or $OLDPWD/....||$ pwd
$ cd ~/lib
$ echo ~-/bin
As you can see, the tilde shorthand is a great time saver.
Pattern Expressions A pattern expression is any word consisting of ordinary characters and one or more shell pattern-matching characters. The pattern-matching characters are the familiar *, ?, and [...] from the Bourne shell, as well as any of the extended pattern-matching expressions shown in Table 11.2.
|*(pattern[|pattern]...)||Matches zero or more occurrences of the specified patterns. For example, time*(.x|.y) matches the filenames time, time.x, time.y, time.x.x, time.y.y, time.x.y, and time.y.x, but it doesn't match the filename time.z.|
|+(pattern[|pattern]...)||Matches one or more occurrences of the specified patterns. For example, time+(.x|.y) matches time.x, time.x.x, time.y, time.x.y, and so on, but it doesn't match time.|
|?(pattern[|pattern]...)||Matches any one of the patterns. It won't concatenate or repeat patterns to match files, unlike *(pattern). For example, time?(.x|.y) only matches time, time.x, and time.y, but it doesn't match time.x.x.|
|@(pattern[|pattern]...)||Matches exactly one occurrence of the pattern. For example, time@(.x|.y) matches time.x or time.y, but it doesn't match time, time.x.x, or time.x.y.|
|!(pattern[|pattern]...)||Same as *, except that strings that would match the specified patterns are not considered matches. For example, time!(.x|.y) matches time, time.x.y, time.0, and everything beginning with time except for time.x and time.y.|
CAUTION: You'll notice that the expressions *(pattern[|pattern]...) and +(pattern[|pattern]...) will match any combination of the specified pattern. This can be both useful and dangerous. If in doubt, use echo to find out what files the patterns will match. You won't be popular if you end up removing the system configuration by mistake!
Note that the definition of pattern expressions is recursive. Each form contains one or more pattern strings. This means that nested pattern expressions are legal. Consider, for example, time*(.[cho]|.sh). It contains the pattern [cho] inside the pattern expression, which causes it to match time.sh, time.c, time.h, time.o, time.sh.c, time.c.o, and so on. The pattern time*(.*(sh|obj)) matches the filename time.sh or time.obj.
The main value of these extended pattern-matching expressions is in enabling you to select a subset of files without having to list each filename explicitly on the command line. Pattern expressions also are legal in other contexts where the shell does pattern matching, such as in the expression of the case statement.
Another noteworthy enhancement provided by the Korn shell is a more convenient syntax for command substitutions. Remember from Chapter 10, "The Bourne Again Shell," that a string quoted with backquotes (´command´) is replaced with the standard output of command. The backquote notation isn't easy to use, though. The Korn shell supports the following alternative form in addition to the standard Bourne shell backquote notation:
where command-list is any valid list of commands. In its simplest form, a command list is a list of commands separated by semi-colons. Not only does the parenthesized form avoid the problem of recognizing backquotes on printed listings, but it also acts as a form of quoting or bracketing. You can use all the standard quoting forms inside the parentheses without having to use backslashes to escape quotes. Furthermore, the parenthesized form nests; you can use $() expressions inside $() expressions without difficulty.
For example 'ls' can be replaced with $(ls). Similarly, 'ls;who' can be replaced with $(ls;who).
For directory movement, the Korn shell supports two new forms of the cd command:
cd - cd oldname newname
The command cd - is especially helpful. It switches back to the directory you were in before your last cd command. This command makes it easy for you to switch to another directory temporarily and then move back to your working directory by typing cd -. The PWD and OLDPWD variables are maintained to carry the full pathnames of your current and previous directory, respectively. You can use these variables for writing commands to reference files in a directory without typing the full pathname.
You can use the cd oldname newname command to change a component of the pathname of your current directory. This makes lateral moves in a directory structure somewhat easier. Suppose that your current directory is /usr/prod/bin and you want to switch to the directory /usr/test/bin. Just type the command cd prod test. Similarly, the command cd usr jjv switches from /usr/prod/bin to /jjv/prod/bin, assuming that the latter directory exists.
The command-aliasing feature of the Korn shell is certainly one of its most attractive and flexible enhancements over the Bourne shell. It's an enhancement you'll start using right away.
When you define a command alias, you specify a shorthand term to represent a command string. When you type the shorthand term, it is replaced during command execution with the string it represents. The command string can be more than just a command name; it can define options and arguments for the command as well.
You might have one or more preferred ways of listing your directory contents, for example. I like to use the -FC options on my ls command when I just want to see what's in the directory. Typing the command ls -FC ... repeatedly all day long, though, would not be one of my favorite things to do. The command-alias feature makes it easy to set up a shorthand for the ls command. You do it like this:
$ alias lx=`ls -FC`
Now, whenever you enter lx on the command line, the command ls -FC is executed.
The alias command is a built-in shell, meaning that it is available to you only when running the Korn shell. It is not part of the UNIX operating system at large. You use the alias command to define new aliases and to list the command aliases currently in effect.
The general syntax of the alias command follows:
alias [ -tx ] [ name[=value] ... ]
The arguments of alias are one or more specifications, each beginning with an alias name. The alias name is the shorthand command you enter at the terminal. After the equal sign (=), you enter the text with which you want the shell to replace your shorthand. You should enclose the alias value string in single quotes to hide embedded blanks and special characters from immediate interpretation by the shell. The -t and -x arguments enable you to manipulate the alias command in different ways. Specifying -t enables you to see all the tracked aliases, and using -x enables you to define an alias as exportable--much in the same way variables are exportable if you use the export command. For more details on these options, see "Using Tracked Aliases" and "Using Exported Aliases" later on in this chapter.
The Korn shell stores alias names and their definitions in an internal table kept in memory. Because the table is not stored in a disk file, you lose your alias definitions whenever you log out or exit the Korn shell. To keep an alias from session to session, you need to define the alias in your logon profile--a file in your home directory named .profile. There's nothing tricky about it. The same command you enter at the keyboard to define an alias works just as well when issued from a logon profile script. Thus, for aliases you want to use over and over, simply type the alias command in your logon profile; you only have to do it once. (For more information about using the logon profile, see "Customizing the Korn Shell," later in this chapter.)
The syntax of the alias command enables you to define more than one alias on a command. The general syntax follows:
alias name=value [name=value]...
You don't usually write multiple definitions on one alias command, because you usually think them up one at a time. In your logon profile, it's a good idea to write only one alias definition per alias command. This makes it easier to add and delete alias definitions later.
After you define an alias, you might want to list the aliases in effect to see your new definition. Simply enter the alias command with no arguments, as in this example:
$ alias true=let false=let lx=ls -FC
In all likelihood, there are a good many more alias definitions in effect than you defined. The Korn shell automatically defines a number of aliases when it starts up, such as when you log on, to provide convenient abbreviations for some Korn shell commands. The true and false definitions fall into this category. The UNIX operating system provides true and false commands, but, as programs, they must be searched for and loaded into memory to execute. As aliases, the shell can execute these commands much more quickly, so these two particular aliases are provided as an easy performance enhancement for the many shell scripts you execute, usually unknowingly, throughout the day.
To use the lx command alias shown in the last example, use it as a new command name, as in this example:
This, by itself, lists all the files in the current directory in a neat, columnar format sorted for easy inspection. To list a directory other than the current directory, use this command:
$ lx /usr/bin
After alias substitution, the shell sees the command ls -FC /usr/bin.
The capability to prespecify command options in an alias is a great help. Even better, you usually can augment or alter prespecified command options when you use the alias. Suppose that you want to add the command option -a when listing /usr/bin so that you can see all dot files in the directory. You might think that you have to type the full ls command, because the lx alias doesn't include an -a option letter. This is not so. The following command works quite well:
$ lx -a /usr/bin
When the shell executes this command, it immediately replaces lx with the alias value string, obtaining the following internal form:
$ ls -FC -a /usr/bin
The ls command, like most other UNIX commands, is comfortable with command options specified in multiple words. In effect, the -a option has been added to the -FC options provided automatically by the alias.
To remove an alias that you or the Korn shell defined previously, use the unalias command:
$ unalias name [ name ... ]
Notice that, just as you can define multiple aliases on one command line, you also can remove multiple aliases with one unalias command.
One of my favorite aliases is the following one for the pg command:
$ alias pg=`/usr/bin/pg -cns -p"Page %d:"`
The pg alias is instructive in a number of ways. Take a look at it in detail.
First, note that the alias name is pg. This is the same as the pg command itself, so, in effect, the alias hides the pg command. You can invoke the real UNIX pg command by using an explicit pathname--calling /usr/bin/pg--but not by the short command pg, which invokes the alias instead.
Choosing the same name for an alias as a real command name is unusual. It implies that you never want to execute the real command directly and that you always want to dress it up with the options specified in the alias.
Because of the way I work, the options -c, -n, -s, and -p should have been built into the pg command; I always want to use them. The -c option causes pg to clear the screen when it displays a new page. On a video terminal, this is more natural and faster than scrolling the lines. The -n option causes pg to execute a command key immediately without waiting for the Enter key to be pressed. All pg commands consist of only one letter. The only reason not to use the -n option is to avoid the slack in performance that results from generating a terminal interrupt for each keypress, which the -n option requires. Single-user workstations and modern high-performance computers don't notice the extra workload, however. Therefore, unless you're working on an old PDP-11, go ahead and specify the -n option for the convenience it adds. The -s option displays messages, such as the current page number, in highlighted mode and usually in inverse video, which makes the non-text part of the display easier to notice or ignore.
The -p option causes the pg command to display the page number at the bottom of each screen. I like page numbering because it gives me a rough idea of where I am in the displayed document. By default, the page number is displayed as a bare number, run on with the rest of the command line. The pg command, however, enables you supply a format for the page number. I specified -p"Page %d:". It identifies the page number with the word Page and provides a colon (:) to separate the page number from the input command line.
Because the page number format string contains characters special to the shell (specifically, an embedded blank), it must be enclosed in quotes. The alias command also requires that the entire alias definition be enclosed in quotes. Therefore, I need a quote within a quote.
If you understood the discussion of quotes in Chapter 9, you also should realize that there are at least three ways to write the pg alias command:
$ alias pg=`/usr/bin/ls -cns -p"Page %d:"` $ alias pg="/usr/bin/ls -cns -p'Page %d'" $ alias pg="/usr/bin/ls -cns -p\"Page %d\""
The first form is the form I chose for the example. The second form embeds a single quoted string inside a double quoted string; it works just as well. The third form uses an escape character to embed a double quote inside a double quoted string. In this case, the shell strips off the backslashes before it stores the alias value. I avoid this form because I don't like to use escape sequences unless I have to. An escape sequence is a two-character sequence, the first character of which is a backslash (\). The second character is the one that is being escaped, which means that the shell will not try and interpret the character in any way and just treat it as it is.
The point here is that alias definitions usually must be enclosed in quotes unless the alias value is a single word. Thus, you must occasionally embed quoted strings inside a quoted string. You should recognize that this need can arise. Be prepared to handle it by making sure that you understand how the shell-quoting mechanism works.
CAUTION: If you do get a handle on how the shell-quoting syntax works, it incites many otherwise nice people to brand you as a UNIX guru. So be careful.
The alias command supports a number of options, including -x (export) and -t (tracking).
An exported alias is much the same concept as an exported variable. Its value is passed into shell scripts that you invoke.
Exporting a command alias can be both helpful and harmful. Exporting the pg alias shown earlier would be helpful, for example, because it would cause pg commands issued by a shell script--many UNIX commands are implemented as shell scripts--to work as I prefer. On the other hand, if you define an alias for the rm command that always prompts the user before deleting a file, you might be inundated with requests from system-supplied shell scripts to delete temporary files that you've never heard of.
Use the command alias -x to display only those command aliases that are exported. When used in the form alias -x name, the alias name is redefined as an exported alias; it should have been defined previously. To define a new exported alias, use the full form
alias -x name=value
By default, the Korn shell automatically creates a tracked alias entry for many of the commands you invoke from the keyboard. This feature helps to improve performance. When an alias is tracked, the Korn shell remembers the directory where the command is found. Therefore, subsequent invocations don't have to search your PATH list for the command file. Essentially, the alias for the command simply is set to the full pathname of the command.
You can display the commands for which a tracked alias exists by using the command alias -t.
To request explicit tracking for a command you use frequently, use the form
alias -t name
If no alias exists with the given name, the Korn shell performs a path search and stores the full pathname of the command name as the alias value. Otherwise, the shell simply marks the alias as tracked for future reference.
Note that you generally don't set the tracked attribute for command aliases that you write--that is, when the alias name differs from the alias value. The values for tracked aliases usually should be set by the Korn shell. You can achieve the effect of a tracked alias by supplying the full pathname of the command in the alias value; this eliminates path searches. The lx alias shown earlier, for example, would be better written as
alias lx=`/usr/bin/ls -FC'
This would achieve the same effect as tracking.
As a final example, suppose that the vi command is not in the list when you issue the command alias -t, but that you know you will be using the command fairly frequently. To request tracking for the vi command, simply issue the command alias -t vi.
One of the major reasons for name tracking is that the Korn shell takes account of the possibility that your search path--the value of the PATH shell variable--may include the directory . (dot), which is a reference to your current directory. If you switch to another directory, commands that were available might become unavailable, or they might need to be accessed by a different pathname. Alias tracking interacts with the cd command to keep the full pathnames of tracked aliases current. In other words, alias tracking keeps track of the proper full pathname for commands as you switch from directory to directory and create, remove, or relocate executable files. You can use the set command to toggle alias tracking on and off. Typing
set -o trackall
forces the shell to track every command you use, whereas
set +o trackall
switches the tracking off.
Because the Korn shell is a rather sophisticated program, it deals with many human-interface issues that might be resolved in two or more ways. To help you use the shell in ways most convenient to you, the shell enables you to choose how it behaves by setting options.
You can set Korn shell options in two ways: with the ksh command when you invoke the shell and with the set command from within the shell after you've started it. Options that you don't set explicitly take on a default value. Thus, you never need to bother with option settings unless you want to.
The ksh command generally is issued on your behalf by the UNIX logon processor, using a template stored in the /etc/passwd file for your logon name. Generally, the system administrator constructs the password entry for you, but unless he's very busy or very mean-spirited, he'll be happy to adjust your password entry to invoke the shell with your preferred settings. Of course, you can replace your logon shell with the Korn shell at any time by using this command:
$ exec ksh options ...
The exec statement you encountered in your study of the Bourne shell does the same thing under the Korn shell. It replaces the current shell with the command named as its first argument--usually also a shell, but perhaps of a different type or with different options and arguments.
The syntax of the ksh command follow:
ksh [ +/-aefhkmnpstuvx- ] [-cirs] [+/-o option] ... [+/-A name] [arg ...]
The -c, -i, -r, and -s options can be specified only on the ksh command line. All the other options can be specified on the set command as well.
Table 11.3 lists the options specifiable only on the ksh command line.
|-c||Command||The first (and only) arg is a command. The -c option prevents the shell from attempting to read commands from any other source. It merely executes the command given as arg and then exits. This option is not used often from the keyboard or from within shell scripts. It most often is used internally by programs written in the C language.|
|-i||Interactive shell||Forces the shell to behave as though its input and output are a terminal. Usually, you don't need to specify the -i option explicitly. Its main purpose is to prevent the abnormal termination of commands invoked by the shell from terminating the shell itself.|
|-r||Restricted shell||The Korn shell runs as a restricted shell and prevents the user from using the cd command, modifying the PATH variable, redirecting output, and invoking a command by its full pathname. This option generally is of interest only to the system administrator for setting up specialized user accounts. The Korn shell also starts off as a restricted shell if the first character of its name when invoked is an r. Copying (or linking) ksh to rksh, for example, and then running rksh gives the same result as ksh -r. The reason for using the rksh form is that ksh -r isn't always guaranteed to run a restricted shell if it is defined as a logon shell in the password database /etc/passwd.|
|-s||Standard input||The Korn shell doesn't activate the protections against abnormal termination given by option -i. The shell reads commands from standard input until the end-of-file character and then exits normally. This is a handy option, because it enables you to pipe a stream of commands to the shell for execution.|
Table 11.4 lists additional options you can specify on the ksh command or the set command. You can specify options with a letter in the usual way (for example, -a) or by name (for example, -o allexport). An option that has been set explicitly or by default can be turned off with the + flag, as in +a or +o allexport.
|-a||The equivalent option name is allexport. All variables are treated implicitly as exported variables. You don't need to invoke the typeset -x command or export alias to export the variable. A variable becomes eligible for export when it is defined, whether by the typeset statement or by an assignment statement. The typeset-x command and export alias are permitted, but they have no additional effect.|
|-e||The equivalent option name is errexit. Any command returning a non-zero exit code causes immediate termination of the shell. When this option is set within a shell script, only the shell script is terminated.|
|-f||The equivalent option name is noglob. Filename expansion is disabled. Wildcard expressions are treated literally and, with the -f option in force, have no special meaning or effect. You might use set -f and set +f to disable wildcard expansion for a short range of statements.|
|-h||The equivalent option name is trackall. Every command issued is defined automatically as a tracked alias, just as though you executed alias -t xxx in front of each command. The -h option is set to on by default for non-interactive shells. Commands that specify a full pathname or that use names not valid as command alias names are not tracked.|
|-k||The equivalent option name is keyword. When -k is set, command arguments with the form name=value are stripped from the command line and are executed as assignment statements before the command is executed. The assignment is exported temporarily for the duration of the one command. The effect is equivalent to adding keyword arguments to the shell language and to UNIX commands and shell scripts that support this kind of argument. Most UNIX commands and shell scripts, however, do not support keyword arguments. Therefore, the -k option has little real application.|
|-m||The equivalent option name is monitor. -m runs commands that you launch in the background--using the & shell operator--in a separate process group, automatically reports the termination of such background jobs, and enables use of the jobs command for managing background jobs. If -m is not set, commands launched with the & operator execute in the same manner as with the Bourne shell, and job control is not in effect. The default is to enable this option automatically for interactive shells.|
|-n||The equivalent option name is noexec. -n causes the shell to read and process commands but not execute them. You can use this option in the form ksh -n shell-script-filename to check the syntax of a shell script. You probably won't want to use this option with your logon shell.|
|-p||The equivalent option name is privileged. The -p option is useful for script writers. A shell script file that has the Set User ID bit, the Set Group ID bit, or both will, when invoked by the Korn shell, have the effective User ID and effective Group ID set according to the file permissions, the Owner ID, and the Group ID; also, the -p option will be on. In this mode, the shell script enjoys the permissions of the effective User ID and Group ID--not those of the real user. Setting the -p option off--for example, with set +p--causes the Korn shell to set the effective User ID and Group ID to those of the real user, effectively switching to the user's rather than the file's permissions. You subsequently can use the set -p command to revert to Privileged mode. Not all versions of the Korn shell support this definition of the -p option; only the more recent UNIX operating system releases include this facility.|
|-s||When used on the set command, -s sorts the arg command arguments into alphabetical sequence before storing. When used with the ksh command, the -s option reads commands from the standard input (see Table 11.3).|
|-t||The Korn shell, when invoked with the -t option, reads and executes one command and then exits. You should set the -t option with the ksh command instead of with the set command.|
|-u||The equivalent option name is nounset. -u causes the shell to generate an error message for a reference to an unset variable--for example, referring to $house when no value has been assigned to house. The default behavior is to replace the variable reference with the null string. This option is useful to script writers for debugging shell scripts.|
|-v||The equivalent option name is verbose. Each command is printed before scanning, substitution, and execution occur. This is useful for testing shell scripts when used in the form ksh -v shell-script-filename or with set -v and set +v from within a shell script to force the display of a range of commands as they are being executed.|
|-x||The equivalent option name is xtrace. -x causes the Korn shell to display each command after scanning and substitution but before execution. Each line is prefixed with the expanded value of the PS4 variable. Using this option enables you to see the effects of variable and command substitution on the command line. When used in the form ksh -x shell-script-filename the -x option is a handy debugging tool for script writers.|
|--||Used with the ksh or set command, this option forces interpretation of the remaining words of the command line as arguments rather than options--even for words beginning with - or +. The -- option often is used with the set command for setting new values for the positional parameters, because it ensures that no substituted values are construed as set statement options.|
CAUTION: Use caution when writing scripts that will use the privileged option. A badly written script may give potential attackers doors they need to access a more privileged user.
In addition to the letter options listed in Table 11.4, the -o keyletter supports the additional named options listed in Table 11.5.
|bgnice||Requests that the shell automatically reduce the priority of background jobs initiated with the & shell operator as though the nice command had been used.|
|emacs||Invokes the EMACS Edit mode. EMACS editing remains switched on until set +o emacs or set -o vi is entered.|
|gmacs||Invokes the GMACS (Gosling EMACS) Edit mode with the alternative definition of the Ctrl+T transpose function.|
|ignoreeof||Requests that the shell ignore an end-of-file character entered at the beginning of the command line. Ordinarily, an EOF character entered in this position causes the shell to terminate. You can set this option to avoid accidentally terminating the shell. You must use the exit command to terminate the shell and log out.|
|markdirs||Causes wildcard expansion to append a slash (/) to any generated pathnames that are the pathnames of directories.|
|noclobber||Modifies the behavior of the > redirection operator to inhibit the overwriting of existing files. If you name an existing file after >, the shell writes an error message and doesn't open the output file. Use >| to redirect output to an existing file when noclobber is set.|
|nolog||Inhibits the storing of functions in your command-history file.|
|vi||Enables the vi Edit mode with line input. Line input provides only a subset of the features of vi command editing, but it provides better performance than the viraw option. You can switch off vi Edit mode with set +o vi or set -o emacs.|
|viraw||Enables vi Edit mode with character input. Character input provides all the features of vi Edit mode but with more overhead than the vi option.|
The -A option can be used on the ksh command line or the set command to define an array variable with initial values. When you specify -A, the next argument must be the name of the array variable to be initialized. Subsequent arguments are stored as consecutive elements of the array, beginning with element 0. The -A option resets any previous value of the array variable before it assigns new values. Thus, the ending value of the array consists of only those arguments specified as arg.
The +A option assigns the arg values successively, starting with element 0, but it doesn't reset any previous values of the array. Thus, if the array variable previously had 12 values and only six values were provided with +A, after execution, the first six elements of the array would be the arg values and the last six elements would be left over from the previous value of the array.
The significance of the arg values depends on the options specified. If option -A is specified, the values are taken as initial array element values. If option -s or -i is specified, or if option -i defaults because the shell input is a terminal, the arg values are used to initialize the positional parameters $1, $2, and so on. If option -c is specified, the first arg is taken as a command string to be executed. If none of the options -A, -c, -i, or -s is specified, the first arg is taken as the name of a file of shell commands to be executed, and subsequent arg values are set temporarily as the positional parameters $1, $2, and so on during the file's execution.
Command history and command editing are somewhat interrelated features. To fully use all the benefits of command editing, however, you need an understanding of how command history works.
Command history is simply the automatic recording of commands that you enter in a numbered list. The list is kept in a special disk file in your home directory to preserve it from logon session to session. Therefore, when you log on, the command-history list from your previous session is available for reference and use. New commands you enter are added to the end of the list. To keep the list from growing too large, the oldest commands at the beginning of the list are deleted when the list grows to a certain fixed size.
You don't need to do anything to activate the command-history feature, and you don't need to specify its maximum size. Its operation is completely automatic. Your only mission, should you decide to accept it, is to use the list to make your life easier.
You can use the command-history list in one of three ways:
NOTE: Performing command editing with the fc command, although a convenient and useful feature of command history, is not the same as the command-editing feature discussed later in the "Command Editing" section.
Now take a closer look at these commands for viewing and manipulating command history.
The command history command displays the commands in the command-history list. Each command is listed with a line number preceding it. The line number uniquely identifies each command in the history list, and it is one way you can refer to a specific line in the history list--for example,
$ history  cd /usr/home/jim/src/payapp/pay001  vi main.c  cc -I../include -o main main.c  fgrep include *.c | grep `^#'  vi checkwrite.c checkfile.c checkedit.c  lint -I../include checkfile.c >errs; vi errs  vi checkfile.c  cc -I../include -o checks check*.c  cp checks /usr/home/jim/bin
NOTE: The history command is actually an alias for the fc command--specifically, for fc -l.
The complete syntax for the history command follows:
history [first] [last]
For first, specify the first line to be displayed. You can designate a specific line directly by its line number--for example, history 35--or as a number of lines back from the current line--for example, history -10. You also can give the command name of the line from which the display should begin--for example, history vi. The Korn shell looks backward from the current line until it finds a command beginning with vi and then displays lines from that point forward.
For last, specify the last line to be displayed. If you omit last, history lines are displayed from first up to the current, most recently entered line in the command history. You can use an actual line number, a relative line number, or a command name to designate the last line to be displayed.
If you omit both first and last, the Korn shell lists the last 16 lines of history.
TIP: You won't know what line numbers to use until you first list some history. Most people begin a search of command history without any operands. If you want to see more lines before line number 160, you might want to try history 140.
The r command enables you to reexecute a command from the command-history list. The r command itself isn't added to the history, but the command you reuse is added.
NOTE: The r command is actually a preset alias for the fc command--specifically, fc -e -.
The general syntax for r follows:
r [ old=new ] [ line ]
If you omit line, the most recently entered command is reexecuted.
Specify a line number (25), a relative line number (-8), or a command name (vi) for line to designate the command you want to reuse. As with the history command, if you specify a command name, the most recently entered command with that name is reused.
You can modify a word or phrase of the reused command by using the syntax old=new. Suppose that the command history contains the following line:
135 find /usr -type f -name payroll -print
You could reuse the find command, changing only the filename payroll to vendors, like this:
$ r payroll=vendors find
The r command echoes the line that will be executed, showing any changes that might have been made. For example, the r command here yields the following output:
$ r payroll=vendors find find /usr -type f -name vendors -print
The fc (fix command) command is a built-in Korn shell command. It provides access to the command-history list. Forms of the fc command enable you to display, edit, and reuse commands you previously entered. The Korn shell automatically defines the alias names history and r for you to reduce the amount of typing needed to perform simple history functions.
The syntax of the fc command follows:
fc [ -e editor ] [ -nlr ] [ first ] [ last ]
When invoked with no options, the fc command selects a line from the command history using the values of first and last, invokes the default command editor, and waits for you to edit the command or commands selected. When you exit the editor, by filing the altered command text or by quitting the editor, the commands are executed.
The fc command actually copies the selected commands to a temporary file and passes the file to the text editor. The contents of the file after editing become the command or commands to be executed.
For example, if you enter the command
$ fc vi
where vi represents the value of first, the Korn shell copies the most recent vi command to a temporary file. The temporary file has an unrecognizable name, such as /usr/tmp/fc13159, and is located in a directory designated for temporary files. The file you actually edit is /usr/tmp/fc13159. Regardless of whether you change the text in file /msr/tmp/fc13159, the Korn shell executes its contents immediately after you exit the editor.
You can specify the command or commands to be processed in the following manner:
135 mkdir paywork 136 mv paymast/newemps paywork 137 cd paywork 138 vi newemps 139 payedit newemps
The first and last command-line selectors don't have to use the same formats. You could select line 145 of the history list through the fifth-to-last line by entering fc 145 -5, for example.
By default, the fc command invokes a text editor on the selected lines and reexecutes them after editing. You can modify this default behavior with the options shown in Table 11.6.
|-e||Editor||Use the -e option to override the Korn shell's default editor. To use the
vi editor to modify and reuse commands, for example, type fc -e vi .... Use
fc -e vi ... to override the default editor.
The special format -e - suppresses the use of an editor. The selected lines are executed immediately with no opportunity to change them. This form of the fc command--as in fc -e - 135--is equivalent to the r command. When you use this form, the second dash must be a word by itself. The command fc -e - 135 immediately reexecutes line 135 of the command history, whereas the command fc -e -135 attempts to edit the most recent command in the history list with an editor named -135, which probably doesn't exist. Alternatively, the command fc -e- 135 generates another kind of error, because -e- isn't a valid option of the fc command.
|-l||List||The selected lines are listed. No editor is invoked, and the lines are not reexecuted. The command fc -l is equivalent to the alias history.|
|-n||Numbers||Use the -n option to suppress the printing of line numbers in front of the command history. The -n option is meaningful only in combination with the -l option--for example, fc -nl.|
|-r||Reverse||The -r option causes the command history to be printed in reverse order. The most recently entered command is shown first, and successive lines show progressively older commands. Use the -r option with the -l option--for example, fc -lr.|
Command editing is arguably the most important extension of the Bourne shell included in the Korn shell. It is a great time-saver, and it makes the shell much easier to use for UNIX beginners.
The basic idea of command editing is to enable you to use common keys on most terminal keyboards to correct keying errors as you enter commands.
To bring this basic idea to reality, the Korn shell must have some support from the terminal you're using. If you're going to backspace and retype a character, for example, it would be helpful if the terminal is capable of backspacing, erasing a character already displayed, and typing a new character in its place. For this reason, command editing is most useful with video-display terminals. Hard-copy terminals such as teletypes are inappropriate for use with the command-editing feature of the Korn shell.
The Korn shell supports two distinct styles of command editing: vi Edit mode--named after the vi text editor--and EMACS Edit mode--named after EMACS. If you're familiar with either of these editors, you can begin to use command editing immediately.
Before you can use command editing, you first must activate it. Until you do so, the Korn shell command line works much the same as the Bourne shell: Everything you type goes into the command line indiscriminately as text, including control and function keys. This is a compatibility feature you'll want to disable as soon as possible--typically, by activating command editing in your logon profile.
To enable vi Edit mode, enter the following command line or place it in your profile (see "Customizing the Korn Shell," later in this chapter):
set -o vi
To enable EMACS Edit mode, enter the following command line or place it in your profile:
set -o emacs
If you're not familiar with the vi or EMACS text editors, but you want to use command editing, read through the following sections and choose the editing interface you find most natural.
vi Edit mode uses the editing commands and methods of the vi text editor, although with some minor differences due to the fact that you're editing only one line of text and not an entire file.
You can activate vi Edit mode by entering this command:
set -o vi
If you prefer to always use the vi Edit mode, add the command to your profile. Note that you can't have the vi and EMACS Edit modes both active at once, though. You can switch between them or shut them both off.
Just like the vi editor, vi command-editing uses two modes: Command and Input. Normally, your keyboard is in Input mode, and every character you type is entered into the command line. To enter Command mode, press ESC. In Command mode, the upper- and lowercase letters of the keyboard represent editing commands, and pressing a key causes an editing action. If no command corresponds to a given key, pressing it in Command mode causes the terminal to beep; you cannot enter text in Command mode. This error is the most common mistake beginners make with vi-style editing. It is a stumbling block responsible for the vi editor's miserable reputation as a text editor.
Pressing the Enter key always returns you to Input mode. After you make any editing changes to the line, you can press Enter no matter where your cursor is in the line to enter and execute the command.
CAUTION: Keystrokes you type while in Command mode are not displayed. You can see only the effect of an edit command--not the command itself. This can be unsettling if you're inexperienced with the vi style of editing or if you're entering a command of more than a few keystrokes.
TIP: If you forget whether you're in Command or Edit mode, the invisible nature of Command mode can make your keyboard appear to go wild and not respond to your input in any recognizable fashion. If this happens to you, the best thing to do is to try to cancel the current line completely with the kill function--normally, by pressing the @ or Ctrl+U keys. If all else fails, press the Enter key. Pressing the Enter key might give you an error message when it attempts to execute a garbled command, but at least it is guaranteed to return you to Input mode.
Table 11.7 summarizes the vi Edit mode commands. As you'll notice if you're already familiar with vi, nearly all the vi commands are supported--even those that cause movement upward and downward in a file. Commands that move from one line to another actually cause movement in the history file. This enables you to browse through the command history, select a command, modify it if necessary, and reenter it--all with a few simple keystrokes.
Some commands can be prefixed by a count--a non-zero number. A count causes the command to be repeated that number of times. For example, B moves backward one word, but 12B moves backward 12 words. If you don't specify a count, it defaults to 1.
A few commands--notably c (change), d (delete), and y (yank)--must be followed by a cursor-motion command. Such commands are marked with the right-arrow symbol ([ra]). Using cursor-motion commands is discussed after Table 11.7.
|a||Inserts text after the cursor.|
|A||Inserts text at the end of the line.|
|[n]b||Moves backward one word.|
|[n]B||Moves backward one blank-delimited word.|
|C||Changes to end of line.|
|dd||Discards the entire current line.|
|[n]D||Deletes to end of line.|
|[n]e||Moves to end of current word.|
|[n]E||Moves to end of blank-delimited word.|
|[n]fc||Moves cursor to next c in current line.|
|[n]Fc||Moves cursor to previous c in current line.|
|[n]G||Moves to the last--least recent--line in the command history. If nG is entered, it selects line n from the command history.|
|[n]h||Moves the cursor one position to the left.|
|i||Inserts text before cursor.|
|I||Inserts text in front of the first nonblank character of the line.|
|[n]j||Moves down one line--that is, to a more recent history line. This command discards whatever you have typed on the current line.|
|[n]k||Moves up one line--that is, to a less recent history line. This command discards whatever you have typed on the current line.|
|[n]l||Moves cursor one position to the right.|
|n||Repeats the previous / or ? command.|
|N||Repeats the previous / or ? command but in the reverse direction. It causes a / command to be repeated as the equivalent ?, and ? to be repeated as the equivalent of /.|
|[n]p||Inserts text into the edit buffer after the current cursor position.|
|[n]P||Inserts text into the edit buffer before the current cursor position.|
|[n]rc||Replaces the current character with c. A repeat factor replaces n consecutive characters with c.|
|R||Replaces characters in the current line--Replace mode. This command differs from C in that it does not discard characters following the cursor; only as many characters as you type are replaced. You end Replace mode by pressing Enter or ESC.|
|S||Deletes entire line and enters Input mode.|
|tc||Moves cursor to the next c in the line.|
|Tc||Moves cursor to the previous c in the line.|
|u||Undoes the last text change. You can undo the previous u command. Successive u commands alternate between the original and the changed form of text.|
|U||Undoes all changes to the current line.|
|[n]v||Edits the current command--or line n of the history file--with the vi editor. When you exit vi, the edit file is executed as commands, one per line.|
|[n]w||Moves cursor to next word.|
|[n]W||Moves cursor to next blank-delimited word.|
|[n]x||Deletes characters after the cursor.|
|[n]X||Deletes characters before the cursor.|
|[n]y[ra]||Yanks text into the edit buffer.|
|yy||Yanks (copies) the entire current line.|
|Y||Yanks (copies) text to the end of line.|
|^||Moves cursor to the first character of the line that is not a space or tab.|
|0||Moves cursor to the first position of the line.|
|$||Moves cursor to the last character of the line.|
|[n]-||Moves to the preceding line in the command history.|
|[n]+ $||Moves to the next line in the command history. Use + only if you have used - or k to move backward in the history file. Use G to skip back to the earliest line in the history file.|
|[n]| $||Moves to the nth character of the line--that is, to column n.|
|[n]_ $||(underscore) Inserts the last (nth) word of the previous command.|
|/string$||Selects the most recent line in command history that contains string. string cannot be a regular expression.|
|/^string$||Same as / except that it selects only a line that begins with string. That is, / selects a line that contains string anywhere in the line, but /^ looks only for lines that begin with string in column 1.|
|?string$||Searches forward in the history file--that is, toward more recent lines--until it finds a line that contains string. The selected line replaces the current line. string cannot be a regular expression.|
|?^string||Same as ? except that it selects only a line that begins with string. That is, ? selects a line that contains string anywhere in the line, but ?^ looks only for lines that begin with string in column 1.|
|; $||Repeats the previous f, F, t, or T command.|
|,||Repeats the previous f, F, t, or T command but reverses the search through the command.|
|~||Inverts the capitalization of the current character.|
|.||Repeats the previous text-modifying command.|
|#||Inserts a pound sign (#) at the beginning of the line. If you then press Enter, the shell treats the line as a comment, and the line is added to the command history.|
|=||Lists filenames in the current directory that begin with the same characters as the current word. The listed filenames are not inserted into the current line, and the current line is not changed. You can use the displayed information to select a file, though, and finish typing a complete filename.|
|\||Appends characters to the word containing the cursor so that the word forms a valid pathname. The shell searches the current directory--or the directory specified by the incomplete word--for filenames that begin with the same characters as the word. Then it appends characters from the matching filenames until a full filename is formed, or, in the case of multiple matches, the filenames differ. This command is a handy way to abbreviate a filename or to enter a filename when you can remember only a few leading characters of the name.|
|*||Replaces the word with the list of filenames in the current directory--or in the directory specified by the word--that all begin with the same characters as the replaced word. This has the same effect as the wildcard expression string* if entered directly, except that the filenames are entered into the command line now instead of during shell processing.|
|Space||Moves cursor to the right. It doesn't change characters spaced over.|
|Backspace||Moves cursor to the left. It doesn't change characters backspaced over.|
|Enter||Executes the current command line.|
|Ctrl+L||Redraws the current line. This command is useful if the screen becomes garbled. It redraws only the display line used for command input--not the entire screen.|
NOTE: Although many vi editors support cursor keys for cursor control, the vi Edit mode does not recognize these keys, so you must use h, j, k, and l to control the cursor.
The vi command-editing feature also supports a few control operations you can use while in Input mode, which are described in Table 11.8. Using one of these operations doesn't require you to switch to Command mode first, and it doesn't switch you to Command mode.
|Enter||Executes the command line. You can press Enter while in Command mode or Input mode, regardless of the current cursor position. If the cursor is somewhere in the middle of the line, pressing Enter doesn't truncate the remainder of the line; instead, it executes the whole line.|
|Erase||Normally the # or Backspace key. This is the erase function defined with the stty command. The cursor is backspaced, and the character at that position is erased.|
|Kill||Normally the @ or ^u (Ctrl+U) character. This is the kill function defined with the stty command. The current line is discarded; the input line is erased and the cursor returns to the start of the line. Notice that this differs from the normal shell action when command editing is not in effect. Normally, the kill function scrolls the discarded line up and starts a new line below it.|
|Ctrl-v||Escapes the next character. It enables you to enter the Erase, Kill, or \ character as data, avoiding the normal control function.|
|Ctrl-w||Deletes the previous word. It is similar to Backspace, but it backspaces over the preceding word instead of the preceding character.|
|\||Escapes the next Erase or Kill character. It is similar to Ctrl+V, but it doesn't escape other commands.|
Most vi commands can be preceded with a repeat factor, shown in the box as [n]. If you omit the repeat factor, the command executes its normal function one time. A repeat factor larger than 1 causes the command to repeat its action the specified number of times. Thus, 2W causes the cursor to skip forward not one but two words, and 7r. replaces seven characters, starting at the cursor position, with seven periods.
Commands shown with the symbol [ra] require a cursor motion command following the main command letter. The c, d and y commands must be followed by a cursor motion command to define the amount of text to be changed, deleted or yanked (copied). The cursor motion command can be any command that, if by itself, would move the cursor beyond the desired text. For example, dw deletes the current word. cte changes text up to, but not including, the next e in the line. y0 yanks the characters from the beginning of the line up to, but not including, the character at the cursor position.
Framing cursor-motion commands to meet your text-editing objectives is your responsibility. No prespecified limitations exist on the method for selecting a range of text; you are free to choose whatever comes naturally to you. Until you are comfortable with the use of cursor-motion commands, however, stick to simple combinations, such as cw or cW, to change a word.
The capitalized cursor-movement commands B, E, and W differ from their lowercase counterparts in their choice of delimiters. The lowercase b, e, and w commands consider a word to end at the next nonalphanumeric punctuation character, which can be a blank or tab but also includes apostrophes, commas, and so on. The B, E, and W commands consider a word to be delimited strictly by blanks or tabs. They skip over, or select, punctuation characters as well as alphanumerics.
Most of the commands leave you in Command mode. A few--a, A, c, C, i, I, R, and S--switch to Input mode to enable you to enter text. If, after entering the text, you are ready to execute the command, simply press Enter. If you want to edit the line some more, however, you must switch back to Command mode. In that case, press ESC after entering the desired text.
Not all commands supported by the vi editor are shown in Table 11.8. Commands not shown are not supported by the built-in vi Edit mode of the Korn shell. Noteworthy omissions include the o and O (open) commands, the m (mark) command, and scrolling commands such as z, H, and M. These omissions are due to the difference between a command editor and a file editor. In a command-editing context, they have no useful purpose.
NOTE: For a fuller discussion of the vi text-editing commands, refer to Chapter 3 in Volume II, "Text Editing with vi, and emacs."
The EMACS Edit mode is designed to parallel the editing interface offered by the EMACS editor. The EMACS editor is not so widely available as the vi editor, but many people feel that its modeless, full-screen editing style is more natural than vi. Be that as it may, a modal editing style is well suited to command editing. Even if you're already an EMACS devotee, you might want to try your hand at the vi Edit mode before discarding it out of hand.
The EMACS Edit mode is activated when you enter this command:
set -o emacs
If you prefer to always use the EMACS Edit mode, you can add the command to your .profile file. Note, however, that you can't have the EMACS and vi Edit modes both active at once. You can switch between them or shut off both of them.
Because the EMACS editing interface is modeless, you always can enter text into the current line. To perform an editing operation, you generally enter a command prefixed by the ESC key. Therefore, commands generally require at least two keystrokes. Because ESC isn't conveniently located on most keyboards, entering a series of editing commands is quite a feat of gymnastics.
The EMACS keyboard commands are described in Table 11.9. Numbered Notes specific to the commands discussed in the Table immediately follow Table 11.9. The commands are listed in alphabetical order by the command letter, with special characters (*, =, and so on) listed first. All commands are one letter, preceded by Ctrl or ESC. As usual, you hold down the Ctrl key while pressing the command letter, but you press and release ESC before pressing the command-letter key. Several notes explaining the table entries are located after this table.
Many commands enable you to specify a repeat count in the form Esc n before the command. The repeat count repeats the action of the command that number of times or specifies a column relative to which the command should operate. The value of n starts at 1. Esc 1 executes the command once; it is the same as omitting Esc n, or column 1 of the current line.
CAUTION: The EMACS Edit mode edits lines--not commands. Command history might contain multiline commands, such as if or while, if you use such commands at the keyboard. The vi Edit mode processes such commands as a single entity, but in EMACS Edit mode, you might need to use the Ctrl+O (operate) command to step through multiline commands when you retrieve them from the command history.
The EMACS command-editing interface is an example of a user interface designed for an alien species, because it obviously requires the use of three hands to perform well. If you are a beginner or a casual user of command editing, you might nevertheless find EMACS Edit mode preferable to vi mode, because, with EMACS, there's no confusion between Command mode versus Input mode. As your proficiency and keyboard speed increase, however, the vi Edit mode becomes a more attractive interface.
|ESC n||Key Sequence||Action|
|Enter||Executes the current line. On some terminals, it is labeled Return.|
|Erase||The stty erase character. It deletes the character preceding the cursor.|
|ESC n||Erase||Backspaces n characters.|
|Kill||Deletes the entire line. When entered twice in quick succession, it causes subsequent Kill characters to print blank lines.|
|\||Escapes the next character, enabling the Erase, Kill, EOF, and ESC characters and Ctrl-x characters to be entered into the current line. The \ itself is discarded. Type \\ to enter a single backslash.|
|ESC ESC||Appends characters to the current word to complete the pathname.|
|ESC Space||Sets a mark at the cursor position.|
|ESC *||Performs a pathname expansion on the current word as though an * were appended and replaces the word with the list of pathnames that match, if any.|
|ESC =||Lists pathnames that match the current word, as though * were appended to the word. The current line is not changed.|
|ESC <||Fetches the least recent line from command history.|
|ESC >||Fetches the most recent line from command history.|
|ESC .||Inserts the last word of your preceding command at the current cursor position.|
|ESC n||ESC .||Inserts the nth word of your previous command at the cursor position.|
|ESC _||Same as ESC ..|
|ESC Ctrl+?||Same as ESC Ctrl+H. (see Note 1)|
|ESC n||ESC Ctrl+?||Same as ESC Ctrl+H. (see Note 1)|
|ESC letter||Invokes the macro defined as an alias named _letter. (see Note 2)|
|Ctrl+] c||Moves cursor to next occurrence of character c in this line.|
|Ctrl+A||Moves cursor to start of line.|
|Ctrl+B||Moves cursor left one character. (see Note 3)|
|ESC n||Ctrl+B||Moves cursor left n characters.|
|ESC b||Moves cursor to beginning of word.|
|ESC n||ESC b||Moves back n-1 words.|
|Ctrl+C||Makes the current character uppercase.|
|ESC n||Ctrl+C||Makes n characters uppercase.|
|ESC c||Makes everything to end of current word uppercase. (see Note 4)|
|ESC n||ESC c||Uppercases n words from cursor position. (see Note 4)|
|Ctrl+D||Deletes one character. (see Note 5)|
|ESC n||Ctrl+D||Deletes n characters. (see Note 5)|
|ESC d||Deletes to the end of the current word.|
|ESC n||ESC d||Deletes to end of nth word right.|
|Ctrl+E||Moves cursor to end of line.|
|Ctrl+F||Moves cursor right one character. (see Note 3)|
|ESC n||Ctrl+F||Moves cursor right n characters.|
|ESC f||Moves cursor right one word.|
|ESC n||ESC f||Moves cursor right n words.|
|ESC h||Same as ESC Ctrl+H.|
|ESC n||ESC h||Same as ESC n ESC Ctrl+H.|
|ESC Ctrl+H||Deletes backward to beginning of current word. (see Note 6)|
|ESC n||ESC Ctrl+H||Deletes backward to beginning of nth previous word. (see Note 6)|
|Ctrl+J||Same as Enter.|
|Ctrl+K||Deletes to end of line.|
|ESC n||Ctrl+K||Deletes characters back to or up to column n.|
|Ctrl+L||Redisplays the entire current line.|
|ESC l||Makes all characters to end of current word lowercase. (see Note 4)|
|ESC n||ESC l||Makes n words from cursor position lowercase. (see Note 4)|
|Ctrl+M||Same as Enter.|
|Ctrl+N||Fetches the next line from the command-history file. Successive presses retrieve more recent lines in progression. (see Note 3)|
|ESC n||Ctrl+N||Fetches the nth line forward from your present position in the command-history file.|
|Ctrl+O||Executes the current line and then fetches the next line from the command history. (see Note 7)|
|Ctrl+P||Replaces the current line with the last line of the command history. Successive presses retrieve consecutively older lines from the command history. (see Note 3)|
|ESC n||Ctrl+P||Fetches the nth line back from the command history.|
|ESC p||Copies text from cursor to the mark into an internal buffer. To set a mark use ESC Space. This will mark the current position internally as a reference point.|
|Ctrl+R string Enter||Searches command history for the most recent line containing string. To repeat the preceding search, omit string.|
|ESC 0||Ctrl+R string Enter||Searches the command history starting at the oldest line forward for the first occurrence of string. To repeat the preceding search, omit string.|
|Ctrl+R ^string Enter||Same as Ctrl-r, except that it matches string only at the beginning of a line.|
|ESC 0||Ctrl+R ^string Enter||Same as ESC 0 Ctrl-r, except that it matches string only at the beginning of a line.|
|Ctrl+T||Transposes the current and next characters. (see Note 8)|
|Ctrl+U||Multiplies count of next command by 4. Thus, Ctrl-u Ctrl-f moves the cursor right four positions.|
|Ctrl+V||Displays the current version of the Korn shell. To redisplay the current line, press any key.|
|Ctrl+W||Deletes characters from cursor to mark. Marks are set using ESC Space.|
|Ctrl+X Ctrl+X||Moves cursor to the mark position, setting a new mark at the old cursor position. This is called swap cursor and mark.|
|Ctrl+Y||Inserts most recently deleted text at the current cursor position.|
NOTE: The sequence Ctrl+? is not to be taken literally. It represents the ASCII Del (127) character. Most terminals generate the Del character in response to the Delete key, in which case ESC Delete is a synonym for ESC Backspace.
NOTE: A macro is defined with the alias shell built-in command. Its name must begin with an underscore (_) and must be followed by one letter. The value of the alias is processed as if you typed the characters of the value at the time of invoking the macro. Thus, sequences such as Ctrl-f in the alias value move the cursor to its current position. The letter used in the macro name should not be b, c, d, f, h, l, or p; these letters already are assigned to EMACS commands.
NOTE: In addition to using the control-key sequences to move the cursor, you can use the cursor-control keys to navigate the history list and move the cursor. The capability to do this depends on how your terminal is set up, though.
NOTE: Changing character case also moves the cursor to the right, spacing over the changed character(s).
NOTE: If the Ctrl-d key is assigned to the EOF function with the stty command, it is interpreted as your EOF key when typed at the beginning of the line. Otherwise, it performs the Delete function.
NOTE: Most terminals generate Ctrl-h for the Backspace key. Some terminals generate the ASCII Del character (0177), though. Therefore, the shorthand ESC Backspace might not work for your terminal.
NOTE: To use the operate (Ctrl-o) command, you must have previously established a position in the command-history file by using Ctrl-p, Ctrl-n, or another history command. Successive presses of Ctrl-o step through lines of command history in the forward--older to newer--direction, executing one line at a time. You have the opportunity to change each line before pressing Ctrl-o to execute it.
NOTE: If set -o gmacs is used instead of set -o emacs, Ctrl-t transposes the current and preceding character, not the current and next. This is the only difference between EMACS and GMACS Edit modes.
You were introduced to the concept of shell variables in Chapter 9. Everything you learned there remains true for the Korn shell. The Korn shell provides some significant extensions to shell variable support, though. Among these is a greatly expanded set of variables that have special meanings to the shell. These variables often are called predefined variables, because the shell provides an initial default value for them when you log on. The Korn shell also supports array variables and enhanced arithmetic on shell variables, both of which are a great boon to shell-script writers. Naturally, the syntax of shell variable references is expanded to support these capabilities.
Variables that have special meaning to the shell fall into two main groups: those you can set to affect the behavior of the shell, and those the shell sets for you to provide information.
Variables whose values are set by the shell include the familiar $@, $*, $#, $-, $?, and $$, as well as the new $!. The new variable $! provides the Process ID of the last command you invoked. It differs from $$ in that the value of $$--your current Process ID--generally is that of the shell itself and doesn't change, whereas the value of $! changes each time you invoke a command. The values of the other shell variables have the same meanings as they do in the Bourne shell.
Table 11.10 lists the named variables set by the Korn shell.
|_||Starts of as the full pathname of the last command you invoked. It then becomes the last argument of the preceding command, though, so if you type after the command ls -l, the value of $_ is -l. This variable also is used by the shell to hold the name of the MAIL file when checking for mail. This variable is not really of any use and is used internally by the shell.|
|ERRNO||The nonzero exit code of the last command that failed. This variable is similar to $?, but it differs because its value changes only when a command fails. Successfully executed commands don't change the value of $ERRNO. This variable is primarily a diagnostic aid for use at the keyboard; it is of little use to shell scripts.|
|LINENO||This variable is meaningful only within a shell script. Its value is the line number of the line in the script currently being executed. You can assign a value to LINENO, but it will be changed by the next shell script you invoke. Or, if it is inside a shell script, it will be changed by the next line executed.|
|OLDPWD||The value of this variable is always the full pathname of the directory that was current immediately before the last cd command. In other words, repeated executions of cd $OLDPWD switch you back and forth between your current and preceding directories. An important use of the $OLDPWD variable is to facilitate cp and mv commands. cd someplace followed by cp filelist $OLDPWD copies files to your original directory without you having to type the full directory pathname. Then use cd $OLDPWD to switch back to your original directory. (In the Korn shell, the shorthand cd - means the same thing as cd $OLDPWD.)|
|OPTARG||This value is set by the getopts command--a new built-in command provided by the Korn shell. (For more information, see "Shell Programming," later in this chapter.)|
|OPTIND||This value is set by the getopts command. (For more information, see "Shell Programming," later in this chapter.)|
|PPID||This value is your current parent Process ID. That is, if $$ is the curre