Bash Terminal – Understanding Control Key Shortcuts Behavior

bashescape-characterskeyboard shortcutsterminal

I am confused about how Ctrl-key combinations work in terminal. In bash man page, there are various combinations such as:

  • C-e – go to end of the line
  • C-f – go one character forward

etc.

But then there are some undocumented shortcuts such as:

  • C-j (OR C-m) for return key.
  • C-h for backspace
  • C-i for tab
    etc.

Are these shortcuts just forgotten to be documented? Or, because

  • C-j is LF
  • C-m is CR
  • C-i is Tab

in ASCII, is this somehow a "default" behavior? In other words, is the behavior for C-j, C-m and C-i not implemented by bash but by something else?

Another question is, when I press C-v and left arrow key, ^[[D appears on screen. I.e, ESC-[-d. But when I press ESC-[-d, the cursor does not move left. What is the reason for this?

EDIT:

Initially, I have thought that when I press C-j, the keyboard directly sends 00001010 to kernel. But then I decided that this is not the case, because using programs such as xev or evtest, I have observed that key presses to Control and j appear as different events. So when I press C-j, the keyboard does not send 00001010, but probably multiple bytes. Then where the conversion of these multiple bytes to 00001010 is done?

Best Answer

The behavior of C-m, C-i, etc. is implemented by bash, but the fact that they're the same thing as Return, Tab, etc. is due to the behavior of the terminal. All terminals behave like this because all terminals have always behaved like this and it's what applications expect. The interface between a terminal and an application is based on characters (in fact, bytes), not on keys, so keys that don't send printable characters and key combinations have to be encoded somehow. See How do keyboard input and text output work? for more on this topic. See also https://emacs.stackexchange.com/questions/1020/problems-with-keybindings-when-using-terminal

TAB is the tab character in ASCII, and that's the same thing as the Ctrl+I character in ASCII. Likewise for the other keys. Terminals send that character both when the user presses Tab and when the user presses Ctrl+I. Ditto for RET (CR) and C-m, for LFD and C-j (which most keyboards don't have), and for ESC and C-[. There's also BackSpace which sends either C-h or C-?, that's an issue of its own.

The configuration of the terminal (stty settings) can additionally come into play, and this affects some of bash's settings (e.g. after stty erase @, bash will treat pressing @ as BackSpace), but not C-m and C-j to submit the current line.

^[[D is Esc [ D, but with a capital D. If you press Esc [ D, bash sees the Left key, due to the declaration of cursor key escape sequences in the termcap or terminfo database. There's no default binding for Esc [ d (it isn't an escape sequence that common terminals send).