Enable vi Command-Line Editing in ksh for Oracle DBA Shells

Enable vi Command-Line Editing in ksh for Oracle DBA Shells

Purpose

Recalling and editing the prior command without retyping it is the single most-used operation in a long DBA shift on an Oracle host. On the Korn shell (ksh) — the default login shell on AIX 7.x, Solaris 11, HP-UX 11i, and many older Oracle 11g/12c reference builds — that operation is gated behind one line in .profile: set -o vi. Without it, the up-arrow key prints a literal escape sequence and the only way to repeat a long RMAN BACKUP DATABASE PLUS ARCHIVELOG ... invocation is to type it again.

With vi-mode enabled, the shell treats the command line as a single-line vi buffer. Press Esc to leave insert mode, then k to walk backward through history, /pattern to incremental-search a previous command, b/w/e to jump words, x/dd/cw to delete, and i/a to re-enter insert mode and edit. The keystroke vocabulary is identical to vi proper, so the muscle memory carries from script editing to command-line recall.

The same one-liner works on pdksh, mksh, and ksh93 — the variants installed across the major commercial UNIX distributions Oracle still supports. Bash also honours set -o vi, so the snippet ports unchanged to Oracle Linux and RHEL shells once a DBA's hands are trained on it.

Code

 1# Add to ~/.profile for the oracle user on AIX/Solaris/HP-UX
 2set -o vi
 3
 4# Optional: remap arrow keys to history/cursor motions while in insert mode
 5alias __A=$'\020'   # up arrow    -> Ctrl-P (previous history)
 6alias __B=$'\016'   # down arrow  -> Ctrl-N (next history)
 7alias __C=$'\006'   # right arrow -> Ctrl-F (forward char)
 8alias __D=$'\002'   # left arrow  -> Ctrl-B (back char)
 9
10# Optional: enable completion on Esc-\ in ksh93 (vi-esccomplete equivalent)
11# ksh93 supports this natively; older ksh88 does not.
12set -o vi-esccomplete 2>/dev/null
1# Verify vi-mode is active in the current shell
2set -o | grep -i vi
3# Expected output:
4# vi              on
5# vi-esccomplete  on   (ksh93 only)

Code Breakdown

set -o vi

Switches the shell's line editor from the default emacs mode (or no-edit mode on bare ksh88) to vi mode. The change takes effect immediately for the current shell; place it in .profile so every new login picks it up. No reverse toggle is required between sessions — sourcing .profile again is idempotent.

Arrow-key remap aliases (alias __A, __B, __C, __D)

In vi-mode, the arrow keys are intercepted as raw escape sequences (Esc[A, Esc[B, etc.) and the shell does not bind them to history motion by default. The four alias lines map the escape-sequence terminators to the control-key equivalents: Ctrl-P for previous-history, Ctrl-N for next-history, Ctrl-F and Ctrl-B for cursor motion. This lets the DBA navigate without dropping to Esc first, while still keeping all the vi command-mode editing keys available after Esc.

set -o vi-esccomplete

ksh93 supports completion-on-Esc-backslash (a vi-mode analogue of Tab completion in emacs-mode). The 2>/dev/null swallows the "bad option" error on ksh88 hosts, keeping a single .profile portable across both ksh dialects.

Key Points

  • Default shell matters. AIX, Solaris, and HP-UX ship ksh as the default for the oracle user; Oracle Linux and RHEL ship bash. Both honour set -o vi, but the surrounding .profile versus .bash_profile filename differs. Set both if you want one recipe to cover every host.
  • Vi-mode is non-modal at first keystroke. A new line starts in insert mode, which is what makes the shell usable without thinking about vi at all. The Esc key flips into command mode, which is when history navigation and editing operators become available.
  • History size is independent of vi-mode. Set HISTSIZE=1000 and HISTFILE=~/.sh_history in .profile to make sure there is actually a history to navigate. The default HISTSIZE on commercial UNIX is often only 128 entries.
  • set -o emacs is the only other option. There is no "off." Removing set -o vi from .profile reverts to whatever the shell's default is — usually emacs-mode on Linux/bash, no editing on bare ksh88. Make the choice explicit either way.
  • bind -m for bash-only remaps. The arrow-key alias trick above is a ksh idiom. On bash, prefer bind '"\e[A": previous-history' in .bashrc. Mixing the two is harmless but a single .profile reads cleaner.

Insights and Best Practices

Pair with HISTFILE and HISTSIZE for real session recall

vi-mode without a sized history is a bicycle without wheels. Add to .profile:

1export HISTFILE=~/.sh_history
2export HISTSIZE=1000

This persists the last 1000 commands across sessions, so the morning DBA can find what the on-call DBA did overnight by tabbing through history rather than checking the audit log.

Use /pattern to search backward, not k to spin

Esc then /restore walks backward to the first command containing the string restore. n jumps to the next older match, N jumps newer. This is dramatically faster than tapping k 80 times to find the last RMAN RESTORE invocation from yesterday.

Reach for fc for the multi-line case

set -o vi is single-line editing. When a previous command was a multi-line PL/SQL block submitted via heredoc, vi-mode collapses it into one line on recall — usually unreadable. The fc built-in opens the previous command in $EDITOR (vi by default) for full multi-line editing:

1fc            # open the previous command in vi
2fc 245        # open history entry 245
3fc -l 240 250 # list history entries 240-250 without editing

fc is included in every ksh and bash and is the right tool when vi-mode runs out of room.

Standardise the recipe across the DBA team

A one-line set -o vi is easy to add, easy to forget, and easy to lose when a new oracle user is created from a default skeleton. Bake the snippet into the team's .profile template in source control alongside the rest of the Oracle environment exports (ORACLE_BASE, ORACLE_HOME, PATH). Every DBA gets the same shell behaviour on every host on day one.

When to Run This

  • During initial setup of a new oracle OS user on AIX, Solaris, HP-UX, or Oracle Linux
  • When inheriting a host where the previous DBA worked in emacs-mode and the muscle memory mismatches
  • After upgrading from ksh88 to ksh93 (re-test vi-esccomplete and arrow-key behaviour)
  • When training a junior DBA who already knows vi and is fighting the shell to recall a long command
  • Anywhere Tab-completion in emacs-mode collides with the team's existing vi workflow

Troubleshooting Common Issues

If set -o vi returns "set: bad option," the shell is sh (Bourne shell), not ksh — common on legacy HP-UX 11.0 boots. Confirm with echo $SHELL and switch the user's login shell via chsh -s /bin/ksh (or /usr/bin/ksh depending on platform).

If arrow keys produce raw escape sequences (^[[A) after set -o vi, the terminal is sending ANSI escapes that vi-mode does not bind by default. Apply the four alias remaps shown above, or accept that history navigation requires Esc-k instead of up-arrow.

If history is empty after every login, HISTFILE is unset or HISTSIZE=0. Export both in .profile and confirm with echo $HISTFILE $HISTSIZE after re-login.

If the prompt feels laggy in vi-mode after pressing Esc, the issue is the escape-timeout interval — the shell is waiting to see whether Esc is the start of an escape sequence (like a remapped arrow key) or a standalone command-mode toggle. Press Esc-Esc to force command mode immediately, or accept the small wait.

References

Posts in this series