For what I have tried, TAB and C-i in .inputrc seems to mean the same thing, whatever I bind to one is bound to the other. I know that originally, it was the same thing and that this behavior is kind of inherited from the old times but nowadays, apart from terminal emulators, all X applications makes the difference between a C-i and a TAB press.

So is there a way to run a terminal command ("complete" for example) when I press the TAB key and run another command when I press C-i?

(the same question applies for C-m and ENTER, C-z, C-d, and all these control sequences that I would like to send by other means than their original binding and apply my own commands to these precious keybindings)

And by the way, if you could explain a little bit the process from a keypress to a shell interpretation that would help me understand. For now I understood that keyboard events are translated by Xmodmap, then by .inputrc and that the result is interpreted by the shell or something like this.

I am currently using Guake, and sometimes gnome-terminal, as terminal emulators.

After following the link proposed in a comment, it appears that the terminal emulator is the element of the chain that transforms TAB keysym from X server into C-i, and sends it to the bash shell because it doesn't understand such things as TAB, ENTER and siblings. So configuring readline itself won't work as it comes after the terminal emulator and before the bash shell. The question could be then precised like this: How to configure my terminal emulator so it translates TAB and C-i, ENTER and C-m, etc, to different pairs of character sequences? Maybe make TAB and ENTER send a new custom escape sequence, that could be mapped in .inputrc later to the original commands, and finally be able to use C-i and C-m for other purposes. Or leave TAB and ENTER and make C-i and C-m send escape sequences instead.

  • Which terminal emulator are you using? If you want to distinguish between tab and C-i then you'll need to configure it for that (not all are configurable). Regarding the general architecture, see How do keyboard input and text output work? May 14, 2015 at 23:19
  • ok, see my edit May 15, 2015 at 0:08
  • @Gilles there are terminal emulators that send keydown/keyups and/or keycodes?
    – jthill
    May 15, 2015 at 0:37

2 Answers 2


The terminal emulator translates events like “the Tab key was pressed” into sequences of characters that the application running in the terminal (bash, in your case) reads. See How do keyboard input and text output work? for a more detailed presentation of this topic.

For historical reasons, a few of keys send a character that's the same as pressing Ctrl with some other character: Tab = Ctrl+I, Return = Ctrl+M, Esc = Ctrl+[. This is because historical physical terminals did this, so applications that run in terminals expect it, so terminals do it.

Both Guake and Gnome-terminal use the VTE library, which does not allow the mapping from key chords to character sequences to be configured. You have the same problem as bash - wrong key sequence bindings with control+alt+space

Xterm has fully configurable key bindings. You can make the Tab key send a tab character (that's the default), or make it send the string hello, or whatever you choose. Xterm is configured via X resources. For example, to make Tab send the escape sequence \e[t when pressed and \e]t when released, put this in your ~/.Xresources:

XTerm.vt100.translations: #override \
  <Key>Tab: string("\033[t") \n\
  <KeyRelease>Tab: string("\033]t") \n\

Or maybe you would leave Tab sending the tab character and make Ctrl+I send something else:

XTerm.vt100.translations: #override \
  Ctrl~Meta~Shift<Key>I: string("\033[a5i") \n\
  Ctrl~Meta Shift<Key>I: string("\033[a6i") \n\

You can then bind \e[a5i to whatever you want in bash and other terminal applications with configurable keybindings.

Note that by convention, multi-character escape sequences start with the escape character (often represented as \e or \033 or \x1b in programming languages and configuration files); some applications may have trouble with escape sequences starting with other characters, and of course you can't have a character that's both an escape sequence and a key of its own, unless you're willing to accept a timeout (that's how it works in applications such as vi where Esc on its own is bound to some functionality). If you define your own key sequences, take care not to clash with the ones sent by function and cursor keys, which are more or less de facto standardized.

  • 2
    Thank you, this kind of knowledge is very difficult to find on the internet, I've been looking for to solve this problem for months every now and then and it's the first time I hear about these possibilities! May 15, 2015 at 11:42

To add to Gilles's excellent answer, in the urxvt terminal emulator the key map can be configured through .Xresources as well: For instance, I added the following line to that file in order to separate Ctrl+Backspace from Ctrl+H (compare this question), so that I could use both key chords in different ways:

# Map Ctrl+Backspace to little-used escape sequence
urxvt.keysym.C-BackSpace: \033[33~

Afterwards I added the following to my ~/.zshkbd to have zsh distinguish between the two key chords:

bindkey "^H" kill-line

# Ctrl + Backspace
bindkey "\033[33~" backward-delete-word

I believe for Ctrl+I and TAB and other applications than zsh it should work similarly (though, in this case one would obviously remap Ctrl+I to a different character).

You must log in to answer this question.

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