dmy

Forward By Word!

written by admin 2735 days ago. Last update at 2013-04-02 16:29:26. Categories admin, bash. Tags , , .

I have to confess that I’m a notorious user of the command line. I do use the command line also on my MacBook Laptop where one of the first actions after having logged in is to open the so called terminal application (Terminal.app, kind of hidden in the Utilities folder). This terminal application is really a step forward compared to xterm or rxvt and is also looking marvelous good.

The hidden gotcha is speed. Where would speed matter you may asking? Well, after having typed in and executed some command, the next command is most often just a minor variation of the previous one. Instead of retyping almost everything again, I let readline’s previous-history function repeat the last (or an earlier) command, move the cursor char-by-char to the desired position where I dare to change something, do the change and eventually execute the command by pushing the RETURN key.

At this point I would like to add a not on the notion used in this small survey about to denote a particular key. Obviously if I mean the key “a” then it’s the small tile on your keyboard with that engraved letter “a”. “A” is bit more complicated cause it is a combination of two “tiles”, namely the “SHIFT” tile and the “a” tile. What you need to do to get the “A” is to hold down tile SHIFT, followed by “a” without releasing SHIFT. So how does the SHIFT key looks like on your keyboard? I have no clue. On my keyboard it’s a tile with a upword-pointing non-filled arrow character. Other keyboard keys of particular importance are the (carriage) RETURN key (originally to move the typewrite’s write position to the line’s beginning), the CONTROL key, the ESCAPE key and usually four navigation keys (usually right and left, up and down).

There must be some convention how to write down a sequence of keystrokes. The one readline uses and which is also being used in this survey is the following: \C means the control key and \e is the escape key. \M is the meta key. I don’t have one on my keyboard, so \e is taking over automatically. Furthermore there are the left and right navigation keys which I’m denoting with <- and ->. Notice that readline does not have a notation for this keys. Instead such a key is represented a key sequence starting with the escape key (\e).

This all works fine except that moving the cursor char-by-char is awfully slow, even in those days with a small super computer right in front of me. It would be really great if I could move forward/backward word-by-word as well. This is of course possible using readline. The function names to do so are forward-word and backword-word.

All fine and well except the default key bindings used for forward/backward word. The standard key binding is \M-f and \M-b. The idea is good. Use \C-f to move forward a char and just switch to the meta key to move forward a word instead. My problem is that I have to press key \e once, then release that key and the press the f key to get the desired effect. That’s much slower than pressing the \C key followed the f key while still holding the \C key. In fact is so much slower that I almost never used the forward move feature. But as I said, forward by char is anoyingly slow.

What I want to do is to assing forward-word with \C--> and backward-word with \C-<-, i.e. I would like to invoke forward-word by holding down the \C key followed by pressing the right arrow (and left arrow for moving backward). This would suite me quite well cause the standard action when pressing the right and left arrow is moving forward or backward a char and this are the keys I’m actually using when moving the cursor (for completness: the up and down arrow move forward and backward in the history).

At this point I had to dig into the documentation to be able to continue:

  1. How to configure readline?
  2. How force bash to re-read the configuration?
  3. How can I see the active bindings?
  4. How can I see the escape characters generated by a key?

The first question is easy. Add or change a (hidden) file named .inputrc right in your home folder. This file is taken into consideration if existing. You can change that setting an environment variable named INPUTRC if you are not happy with the name or the location. In any case, readline will also read the system wide configuration file /etc/inputrc if existing.

Having changed .inputrc, how do I make my terminal application (which runs bash as interactive shell) aware of any changes? You can start a new terminal application (tab or window) or you can type \C-x \C-r in your current one as cheap alternative.

Ok by now, but how can I check the current bindings? When running the bash, use bash’s builtin command bind. For example, you may want to run

% bind -P

to get a relation between readline functions and keys bound to that function. Or you may use bind -p to get a key : function mapping for each function (the output of bind -p would be a valid .inputrc file; it also shows unbound functions – quite useful actually).

Jolly good by now. Except that I have no clue what kind of character sequence is generated by pressing down the right or left arrow key or even what might be generated by additionally holding down the control key (\C). Here another useful readline function, named quoted-insert, comes to rescue. By default, this function gets invoked by \C-v and what it does is, that it inserts the next character you type right there at the cursor’s position.

So you are curious what might be generated by \C followed by holding down the right arrow (->) key? Go ahead and type \C-v \C--> in your terminal and the result on my terminal looks like

$ ^[[5C

Great, now we are almost there. The very last hurdle to overcome is to understand that ^[ is actually the escape key. You can verify this easily using the quoted-insert method explained previously. So what’s left is to add something like this to your local .inputrc and make readline reload that file:

# Make CONTROL - (left arrow) move cursor backward
# one word resp. forward one word
"\e[5D": backward-word
"\e[5C": forward-word

Happy hacking.