Shell Tricks: .inputrc binding fun
If you’ve never explored Bash’s ~/.inputrc
file, there’s a lot of customization you can do in there. From setting completion and Readline options to creating custom keybindings, you can greatly improve your command line efficiency with a little tweaking.
This post is about the latter: custom bindings. Much like OS X keybindings, input keybindings can perform any of the Readline functions, or insert your own text. Using control sequences, you can do things like wrap the existing command, insert common snippets, and perform a variety of completion functions.
As an example of text navigation bindings, you’ll commonly see these:
"\e[1;5C": forward-word
"\e[1;5D": backward-word
The first part (before the colon) is the keybinding, the second half is the command. In this case, they’re Readline commands for moving the cursor by word. \e
represents the Option key (Alt on a PC), and the escape sequences after them are for the left and right arrow keys. This pair allows you to move the cursor left and right by word boundaries using Option-Left and Option-Right.
The Bash reference at Gnu.org offers a complete listing of escape sequences and Readline functions.
To get more interesting, here are a couple examples of modifying the current command using keybindings. You can add these to the ~/.inputrc
file, then run bind -f ~/.inputrc
to source them immediately. (This file is sourced by Bash on login, so in the future you won’t need to do anything to use them.)
Jump to the target folder of the last command and run ls
with Option-x
"\ex": 'cd !$ \015ls\015'
This is great right after you run an extract (tar, unzip, etc.) to a folder or git clone repository destination
command. Pressing it right away will change to the folder where you extracted or cloned to and give you a directory listing.
The \015
represents the enter key, but you can also use \C-m
for the same result.
Undo a directory change with Option-z
"\ez": 'cd -\015'
This one is simple: when Option-z is pressed, run cd -
to return to the previous directory. Again, the \015
presses Enter after inserting the command text so that it runs immediately.
Modify a command in place
Using Readline/Emacs control sequences such as Control-a (beginning of line) and Control-e (end of line), You can move the cursor around as you insert text from a macro.
This one jumps to the beginning, inserts some text, then jumps to the end to insert some more text, then jumps back to the beginning to leave the cursor in a position for editing:
"\e\C-m": '\C-a "$(\C-e)"\C-a'
It assigns Option-Return to wrap the current line as an inline command substitution, and places the cursor back at the beginning. So if the command you type will have output that you want to do something else with, you can hit Option-Return and then type the command that will take the output as the argument. For example, if I’ve typed:
$ find -type f -name "app.js" | head -n 1
it’s going to return the first result as a full path. Maybe I just want to go ahead and print out the contents of that result, so I hit Option-Return and type less
, then hit Return. The resulting command is:
$ less "$(find -type f -name "app.js" | head -n 1)"
Automatically submit output
Here’s a variation that uses the !!
operator to repeat the last command, then pipes the result to fzf
(command line fuzzy finder), returning the result of my selection to whatever command I’ve prefixed.
"\e/": '"$(!!|fzf)"\C-a \C-m\C-m'
To use it, I would type the command I want to run on the resulting selection from the last command’s output, then hit Option-/ (forward slash). So if I’ve run a simple ls *.md
command, I can type mmdc
, and then hit Option-/, and it will re-run the ls command and pipe the contents of the current directory to the interactive selection tool, and whichever file I hit Enter on will be opened in MultiMarkdown Composer (using the mmdc utility).
The \C-a
followed by a space in this macro will jump to the beginning of the line and insert the space, which will prevent the command from being added to shell history (if you have the HISTCONTROL=ignorespace
history option enabled).
Because I have the magic-space history expansion enabled (Space: magic-space
in .inputrc), the space after the \C-a
will also expand the !!
to the full command. I follow it with two \C-m
(Returns) because of the way this shell expansion is set up in my Terminal, but in some cases a single \C-m
(or \015
) will do the trick.
These are just some ideas. The Bash bindings in hstr use this trick to replace Control-R history search with an interactive, fuzzy-matched history tool. If there are certain commands you use frequently, you can make just about anything work with this.
Bonus Tip
In Bash, there are some great but lesser-known default bindings. You may know that Option-. will insert the last argument of the previous command (e.g. running ls ~/Desktop
and then typing cd
and pressing Option-. will turn it into cd ~/Desktop
), but did you know you can actually yank the argument at any index from the last command (without using history
or !
operators)?
Just press Option-[#], where # is the position of the argument you want, then type Option-. to insert it in the current command.
Ryan Irelan has produced a series of shell trick videos based on BrettTerpstra.com posts. Readers can get 10% off using the coupon code TERPSTRA
.