4

I just noticed this by accident.

I use the vi readline mode (run set -o vi in bash) so it is particularly noticeable; in emacs readline mode I don't think Esc does anything, but in vi mode it exits insert mode (enters normal mode).

I don't see Shift-Tab documented in man bash, and it would seem that its interpretation as an Esc key is at a more basic level than bash. Possibly in readline?

It works on Mac OS X as well as Linux.

Where can I find this documented?

2
  • 1
    There are many manuals to review in the 5 part journey of a keypress between keyboard and CPU. 1: The OS hears a keycode from the keyboard and relays that to itself for first processing to affect the windowing system. 2. Your OS transmits some but not all to the focused application, a terminal app. 3. The terminal app hears the keycode, some affect it, some are passed through to bash. 4. bash hears the keycode and uses .inputrc to trap some and pass through still others to gnureadline. 5. gnu readline under the hood traps those keys and relays codes to low level C executable .so files. Commented Jan 12, 2019 at 4:23

2 Answers 2

7

Shift+Tab on several terminals sends an escape sequence like this

ESC [ Z

It was used in the Linux console terminal since 1995, part of xterm since 2002, and used in terminals emulating one or the other of those since then.

In the terminfo description, this would be expressed as

kcbt=\E[Z,

and kcbt is documented in terminfo(5):

key_btab                  kcbt   kB   back-tab key

From the standpoint of parsing, there is no difference between this and pressing some function-key. readline does have special cases for several editing keys (relying on a table of termcap strings in bash's lib/readline/terminal.c), but the termcap "kB" is not part of that.

As an additional complication, a configuration change was made beginning in 2007 which caused shift-tab on the Linux console to send a different escape sequence, i.e.,

ESC TAB

That was reported in 2021, and a fix made to the terminal database. Doing that caused some pain for Emacs developers (see mailing list thread), whose program does check for "kB". But as of May 2022, that appears to be resolved.

Either way, bash ignores that termcap string.

When bash has no termcap information, it relies upon the strings in .inputrc. Failing to find a match in either, that ESC (escape) character will as noted exit insert-mode (that's vi after all).


The escape sequence used for this happens to be the same as the ECMA-48 standard back-tab control sequence. This also is documented in terminfo(5):

   back_tab                    cbt       bt     back tab (P)

Using the same escape sequence for a special key as for a control sequence is not entirely accidental. Hardware terminals used to often provide a local-editing mode in which cursor-movement keys would move the cursor around on the screen without relying on the host to echo the special keys. About half of the terminal descriptions in ncurses' terminal database show this association between special-keys and control sequences:

 439 entries with cbt == kcbt
  73 entries with clear == kclr
 383 entries with cub1 == kcub1
 505 entries with cud1 == kcud1
 885 entries with cuf1 == kcuf1
 868 entries with cuu1 == kcuu1
 174 entries with dch1 == kdch1
 186 entries with dl1 == kdl1
 502 entries with home == khome
  52 entries with ich1 == kich1
 139 entries with il1 == kil1

The counts for cub1 and cud1 are lower than cuf1 and cuu1 because terminal descriptions often use a 1-character backspace or line-feed in preference to a 2-3 character control sequence. Still, that 439 for back-tab says that about a quarter of the terminal descriptions use this particular feature.

Using shift-tab to send a back-tab escape sequence was not done first by Linux console. There are older entries such as the Ann Arbor and the AT&T entries which use this feature. Manuals for the latter on bitsavers are scarce, but the AT&T 610 and AT&T 630 manuals are available.

3
  • This escape sequence comes from the ANSI escape codes that were popularized by DEC VT terminals.
    – chicks
    Commented Oct 25, 2015 at 2:08
  • From your terminfo database, it would seem ESC [ Z as kcbt predate Linux by a long shot. Commented Nov 12, 2015 at 21:08
  • Maybe/maybe not: MSDN does not show this - it shows a different sequence. The earliest reliable source I can see at the moment for this escape sequence is no earlier than around 1995. A book discussing MS-DOS 6.22 matches MSDN's description for instance. Commented Nov 12, 2015 at 22:34
3

it would seem that its interpretation as an Esc key is at a more basic level than bash. Possibly in readline?

It's even lower than that. This is a fundamental property of how terminals work on Unices and Unix-alike operating systems. The operating system sees terminal I/O as a sequence of 8-bit (or even 7-bit) characters. Function keys and extended keys are transmitted as multiple-character escape sequences.

In real terminals, these escape sequences are generated by firmware in the terminal itself. In terminal emulator programs, the terminal emulator turns keystroke data (that it has received through whatever user interface it uses to talk to a keyboard, be that the X Window system, a USB hid device, or a Linux event device) into escape sequences.

Applications such as vim and various line editing libraries try to distinguish them from simple presses of the Esc key by (in effect) timing how long it is between reading the escape character and reading the following characters. If the characters arrive quickly enough one after the other, they are treated as an escape sequence.

Where can I find this documented?

The timeout treatment of escape sequences in input is documented in vim under :help ttimeout and for the Z Shell's ZLE in the zshzle manual page. The basic idea that terminals generate escape sequences is widely documented.

Documentation for the specific escape sequences that are generated is harder to come by. Many, nowadays possibly most, terminals (in particular emulated terminals) speak the escape sequences that have been spoken by DEC VT terminals (when they are in what Digital called "ANSI mode") for many years. DEC provides documentation for its terminals, and you can find it explicitly discussing what Shift+Tab is encoded as in chapter 8 of the VT525 Programmer Information doco.

However: If you are using a kernel virtual terminal on Linux or a BSD, where the terminal emulator program is part of the operating system kernel, the adherence to DEC VT conventions is markedly spotty when it comes to input control sequences. In part this is because operating systems such as FreeBSD actually adhere to the SCO XENIX virtual terminal conventions by default, here. The result is a strange admixture of DEC VT and SCO XENIX that has no correspondence with any real terminal.

The admixture is not just a mismatch between input and output terminal emulations. It is further compounded by the fact that modern configurations attempt to override the SCO XENIX defaults for input control sequences but do so only partially. So, for example: on recent FreeBSDs one can find that F6 is the DEC VT control sequence CSI 1 7 ~, rather than the SCO XENIX sequence that is compiled into the kernel terminal emulator, but Shift+F6 is still the compiled-in SCO XENIX control sequence CSI d rather than the DEC VT control sequence CSI 1 7 ; 2 ~.

And none of this is in the FreeBSD doco at all.

Further reading

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .