, , , ,

The Korn shell (as well as bash and the POSIX shell) has a history mechanism that can be very useful. This history also can be used with line-editing in order to edit the command before entry – and either vi editing or emacs editing can be used.

There are two environment variables that control the history:

  • HISTFILE (stores commands; default $HOME/.sh_history)
  • HISTSIZE (number of commands to keep)

Ksh-93 instroduces two new variables to go with these:

  • HISTEDIT (replaces FCEDIT)
  • HISTCMD (number representing current command)

Neither of those are of much if you use command-line editing.

The location of the history file (contained in HISTFILE) is of some importance. When ksh is used in an environment with NFS-mounted home directories, then the history file will be stored on the NFS volume. This has been known to cause problems in some environments (HP-UX, for one). In these cases, the HISTFILE can be changed to a local directory such as /tmp/.$$_hist_file.

This also brings up another thing of importance: this history file is read by all of the shell logins of that user. So if multiple people are logged into the same account (root for instance), then the same history file is used. This can be confusing, so it may be useful to change the HISTFILE setting for that session to avoid interference.

This history file is also preserved across logins – so some root sessions will disable the history mechanism entirely, preventing others from reading the history file. However, history is quite useful, so a compromise would be to limit the number of commands kept (by changing the HISTSIZE variable).

Line-editing is what makes command history so eminently useful. The mode used (vi or emacs) is chosen based on the setting of the EDITOR and VISUAL environment variables (if set to vi, emacs, or gmacs). Alternately, the option may be chosen directly by using the command:

set -o vi

or the command to choose emacs:

set -o emacs

Once this is done, then standard editing commands can be used. The current line is treated like a single-line window into the shell history file; so going up goes up a line (or command) in the history, and going down goes down a line (command) in the history. In emacs this translates to ^P (previous line) and ^N (next line); in vi it translates to the commands k (up) and j (down). The only special commands are file-completion commands. In both vi and emacs modes, they are similar.

  • ESC-\ (filename completion – or as much as possible; emacs uses META-ESC and vi has an alternate ESC-ESC)
  • ESC-= (outputs list of possible completions)
  • ESC-* (completes file with all matches and enters editing mode)
  • ESC-_ (enter nth word from end of last command – e.g., first from end, second from end, third from end – default is first from end)

In emacs mode, META translates into ESC normally.

Here is an example of a list of possible completions (from ESC-= entered at end of first line):

$ ls -l s
1) sec-2.4.1.tar.gz
2) sec-2.4.1/
$ ls -l s

The command is presented a second time for editing at the end of the list. If ESC-* is pressed the command line becomes:

# ls -l sec-2.4.1 sec-2.4.1.tar.gz

Alternately, if ESC-\ is pressed, the command becomes:

# ls -l sec-2.4.1

It was the lack of understanding of the shell history and command-line editing that held me back from adopting the Korn shell over the C shell for a number of years (I used csh interactively, but wrote scripts in ksh).  I made the switch and never went back.