AI TL;DR
Too lazy to read? Summarize this post with:
Blog Post Publish Date: 2026/10/25
Hacking Your Bash Terminal with Custom Widgets#
This blog post explains how to create custom Bash widgets: Bash functions bound to keyboard shortcuts through the GNU Readline library. It continues GNU Readline: The Magic Behind Terminal Autocomplete, and ends with a widget that reruns the current command every two seconds.
Understand the Basics#
A widget is a function bound to a key that runs while you are editing the command line. In Bash, you write a function and bind it to a shortcut with bind -x, documented with the other Bash builtins.
When Bash runs a function through bind -x, it sets some Bash variables for it. The two that matter most are:
READLINE_LINE: the whole content of the command line.
READLINE_POINT: the cursor position, as an offset into
READLINE_LINE.
The function can read them, and if it changes them, Bash updates the command line when the function returns.
To see them in practice, create a function called debug-hook-variables that prints both, and bind it to Ctrl+x:
### bash function for debugging reserved variables
debug-hook-variables() {
echo ">>> READLINE_LINE: $READLINE_LINE"
echo ">>> READLINE_POINT: $READLINE_POINT"
}
### "\C-x" is the code for `Ctrl+x` shortcut
bind -x '"\C-x": debug-hook-variables'
Now type something at the prompt and press Ctrl+x. For example, with the cursor right after definitely, the output is:
$ definitely| maybe # press `Ctrl+x`
>>> READLINE_LINE: definitely maybe
>>> READLINE_POINT: 10
definitely has 10 characters, so the cursor is at offset 10. Bash also sets READLINE_ARGUMENT and READLINE_MARK, but they’re only needed in more advanced widgets.
Ctrl+xis also the prefix of several default Readline bindings, such asCtrl+x Ctrl+eto edit the command in your editor. BindingCtrl+xalone replaces that prefix in the current session. If you use those bindings, choose another key.
Practical Example: Repeated Command Execution#
Now a useful widget: an alternative to watch. watch runs its command in a new sh -c, so your aliases, such as kgp, aren’t available (see this Stack Overflow thread). This widget runs whatever is on the command line every two seconds when you press Ctrl+x, in your current shell, so aliases work:
repeat-command-widget() {
while true; do
clear
eval "$READLINE_LINE"
sleep 2
done
}
bind -x '"\C-x": repeat-command-widget'
To test it, type a command and press Ctrl+x:
kgp
### press `Ctrl+x`
### stop execution by `Ctrl+c`
kgp runs every two seconds until you press Ctrl+c, just like watch "kubectl get pods".
How to Register the Widget#
Bindings to built-in Readline functions go in ~/.inputrc. A custom Bash widget is shell code, so the function and its bind -x go in ~/.bashrc:
# ~/.bashrc
repeat-command-widget() {
while true; do
clear
eval "$READLINE_LINE"
sleep 2
done
}
bind -x '"\C-x": repeat-command-widget'
The Ctrl+x shortcut is then available in every new Bash session.
Where to Go From Here#
Widgets let you turn any repetitive edit or command into a single key press. Zsh has the same idea with its own line editor, ZLE, and I show the Zsh version of this widget in Hacking Your Zsh Terminal with Custom Widgets. If you’d rather use ready-made widgets, fzf ships widgets for history, file, and directory search.
Key Takeaways#
bind -x '"KEY": function'runs a Bash function when you pressKEY.Inside the function,
READLINE_LINEholds the command line andREADLINE_POINTthe cursor offset. Changing them changes the command line.watchruns its command in a new shell, so your aliases don’t work there. A widget thatevalsREADLINE_LINEin a loop runs in your shell, so they do.Built-in Readline bindings go in
~/.inputrc. Custom widgets are shell code, so they go in~/.bashrc.Ctrl+xis a prefix for default Readline bindings. Binding it alone replaces them.
References#
I’m Carlos Neto, and this blog is where I share my experiences and open source contributions. More about me on my home page. If you have questions or a different approach, contact me on LinkedIn.