NexusCS

GNU Readline

CLI
GNU Readline is a library that provides command-line editing and history capabilities for interactive programs like Bash, GDB, and Python REPL.
bash
shell
terminal
emacs
vi

Getting started

Introduction

GNU Readline provides rich command-line editing with Emacs or Vi keybindings, history navigation, and programmable completion.

Default Mode

Readline defaults to Emacs mode. Most commands use Ctrl key combinations.

# Check current mode in Bash
set -o | grep -E 'emacs|vi'

# Switch to Vi mode
set -o vi

# Switch back to Emacs mode
set -o emacs

Quick Example

# Type a command
echo hello world

# Press Ctrl-a to jump to start
# Press Ctrl-e to jump to end
# Press Ctrl-w to delete word backwards
# Press Ctrl-k to kill to end of line

Configuration File

Readline settings are configured in ~/.inputrc:

# ~/.inputrc
set editing-mode emacs
set completion-ignore-case on
set show-all-if-ambiguous on

Emacs Mode - Movement

Character Movement

Keybinding Description
Ctrl-f Forward one character
Ctrl-b Backward one character
Alt-f Forward one word
Alt-b Backward one word

Line Movement

Keybinding Description
Ctrl-a Beginning of line
Ctrl-e End of line
Ctrl-xx Toggle between start and current position

Screen Movement

Keybinding Description
Ctrl-l Clear screen (keep current line)
Alt-< Move to first history line
Alt-> Move to last history line

Emacs Mode - Editing

Character Deletion

Keybinding Description
Ctrl-d Delete character under cursor
Backspace Delete character before cursor
Alt-d Delete word forward
Alt-Backspace Delete word backward

Killing (Cut)

Keybinding Description
Ctrl-k Kill to end of line
Ctrl-u Kill to beginning of line
Ctrl-w Kill word backward
Alt-k Kill to end of sentence

Yanking (Paste)

Keybinding Description
Ctrl-y Yank (paste) last killed text
Alt-y Rotate kill ring and yank next
Ctrl-] Character search forward
Alt-Ctrl-] Character search backward

Changing Case

Keybinding Description
Alt-u Uppercase word
Alt-l Lowercase word
Alt-c Capitalize word

Emacs Mode - History

History Navigation

Keybinding Description
Ctrl-p Previous history entry
Ctrl-n Next history entry
Alt-< Beginning of history
Alt-> End of history

History Search

Keybinding Description
Ctrl-r Reverse incremental search
Ctrl-s Forward incremental search
Alt-p Reverse search (non-incremental)
Alt-n Forward search (non-incremental)

History Expansion

!!          # Last command
!n          # Command number n
!-n         # nth command back
!string     # Most recent command starting with string
!?string?   # Most recent command containing string
^old^new    # Replace old with new in last command
!!:s/old/new/  # Substitute in last command

History Modifiers

!$          # Last argument of previous command
!^          # First argument of previous command
!*          # All arguments of previous command
!:n         # nth argument of previous command
!:n-m       # Arguments n through m

Completion

Basic Completion

Keybinding Description
Tab Complete filename/command
Alt-? List possible completions
Alt-* Insert all completions
Alt-/ Complete filename

Completion Types

Keybinding Description
Alt-~ Complete username
Alt-$ Complete variable
Alt-@ Complete hostname
Alt-! Complete command

Completion Configuration

# ~/.inputrc
set completion-ignore-case on
set show-all-if-ambiguous on
set visible-stats on
set mark-symlinked-directories on
set colored-stats on
set completion-map-case on

Vi Mode

Enable Vi Mode

# In shell
set -o vi

# In ~/.inputrc
set editing-mode vi
set keymap vi

Insert Mode

Keybinding Description
i Insert at cursor
I Insert at line start
a Append after cursor
A Append at line end
Esc Enter command mode

Command Mode - Movement

Keybinding Description
h Move left
l Move right
w Next word
b Previous word
0 Line start
^ First non-blank
$ Line end

Command Mode - Editing

Keybinding Description
x Delete character
dw Delete word
dd Delete line
D Delete to end of line
c Change
cc Change line
yy Yank line
p Paste after
P Paste before
u Undo

Command Mode - History

Keybinding Description
k Previous history
j Next history
/ Search backward
? Search forward
n Repeat search
N Reverse search

Configuration (.inputrc)

Basic Settings

# ~/.inputrc
set editing-mode emacs
set bell-style none
set completion-ignore-case on
set show-all-if-ambiguous on
set visible-stats on
set mark-symlinked-directories on
set colored-stats on
set colored-completion-prefix on

Conditional Settings

# Apply settings only in Bash
$if Bash
  set completion-ignore-case on
  set show-all-if-ambiguous on
$endif

# Apply settings only in Python
$if Python
  set editing-mode vi
$endif

Custom Key Bindings

# Map Ctrl-Space to complete
"\C-@": complete

# Map Alt-h to show help
"\eh": "\C-ahelp \C-m"

# Map Up/Down to history search
"\e[A": history-search-backward
"\e[B": history-search-forward

# Map Ctrl-p/Ctrl-n to history search
"\C-p": history-search-backward
"\C-n": history-search-forward

Macros

# Define text macro
"\C-xg": "git status\n"

# Multi-line macro
"\C-xp": "ps aux | grep "

# Insert current date
"\C-xd": "\C-a\C-k$(date +%Y-%m-%d) "

Advanced Features

Numeric Arguments

Keybinding Description
Alt-1 to Alt-9 Set numeric argument
Alt-- Negative argument
Ctrl-u Universal argument (×4)
# Delete 5 characters forward
Alt-5 Ctrl-d

# Move 3 words backward
Alt-3 Alt-b

# Repeat command 4 times
Ctrl-u command

Transpose

Keybinding Description
Ctrl-t Transpose characters
Alt-t Transpose words

Special Commands

Keybinding Description
Ctrl-v Quoted insert (literal next char)
Ctrl-g Abort current operation
Alt-r Revert line
Ctrl-_ Undo
Alt-Ctrl-y Yank first argument of previous command

Spell Checking

# ~/.inputrc
set enable-spell-check on

# In Bash 4.3+
shopt -s dirspell
shopt -s cdspell

History Management

History Commands

# View history
history

# Clear history
history -c

# Delete entry number 5
history -d 5

# Append current session to history file
history -a

# Read history file
history -r

# Write history to file
history -w

History Variables

# Bash history configuration
export HISTSIZE=10000           # Commands in memory
export HISTFILESIZE=20000       # Commands in file
export HISTCONTROL=ignoreboth   # Ignore duplicates and space-prefixed
export HISTIGNORE="ls:cd:pwd"   # Ignore specific commands
export HISTTIMEFORMAT="%F %T "  # Add timestamps

History File

# Default history file
~/.bash_history

# Change history file location
export HISTFILE=~/.my_history

# Disable history file
export HISTFILE=/dev/null

Practical Examples

Command Line Editing Workflow

# Type a long command
echo "Hello, this is a very long command"

# Made a mistake? Fix it quickly:
Ctrl-a          # Jump to start
Alt-f           # Move forward to "this"
Alt-d           # Delete "this"
# Type "that"
Alt-f           # Move to "long"
Ctrl-k          # Kill rest of line
# Type new ending

History Search Example

# Previously ran: docker ps -a
# Now need similar command

Ctrl-r          # Start reverse search
# Type: docker
# Press Ctrl-r again to cycle through matches
# Press Enter to execute or Esc to edit

Macro Example

# ~/.inputrc
# Git commit macro
"\C-xc": "git add . && git commit -m ''"

# After setup:
# Type commit message
Ctrl-x c
# Cursor positioned in quotes
# Type message and press Enter

Quick Directory Navigation

# ~/.inputrc
# Jump to common directories
"\eh": "cd ~\n"
"\ep": "cd ~/Projects\n"
"\ed": "cd ~/Documents\n"

# Usage:
Alt-h    # Go home
Alt-p    # Go to Projects

Common Use Cases

Fix Typos Quickly

# Typed: grp pattern file
Ctrl-a          # Go to start
Ctrl-f          # Move to 'g'
Ctrl-f          # Move to 'r'
e               # Insert 'e' (now 'gerp')
Ctrl-f          # Move to 'p'
p               # Insert 'p' (now 'grep')

Reuse Arguments

# Copy file
cp /very/long/path/to/file.txt /another/long/path/

# Edit the file just copied
vim Alt-.       # Insert last argument
# Or: vim !$

Quick Text Manipulation

# Typed: hello world
Alt-b           # Back to 'world'
Alt-u           # Uppercase -> 'WORLD'
Ctrl-a          # Start of line
Alt-c           # Capitalize -> 'Hello'

Gotchas

Alt Key Not Working

Problem: Alt key combinations don't work in some terminals.

Solution:

# macOS Terminal: Enable "Use Option as Meta key"
# Preferences > Profiles > Keyboard > Use Option as Meta key

# iTerm2: Set Left/Right Option key to Esc+
# Preferences > Profiles > Keys > Left/Right Option Key > Esc+

# Or use Esc as alternative:
# Instead of Alt-f, press Esc then f

Ctrl-s Freezes Terminal

Problem: Pressing Ctrl-s freezes the terminal.

Solution:

# Disable XON/XOFF flow control
stty -ixon

# Add to ~/.bashrc to make permanent
echo "stty -ixon" >> ~/.bashrc

Vi Mode Confusing

Problem: Accidentally entered Vi mode, can't type normally.

Solution:

# Press Esc to enter command mode
# Press 'i' to return to insert mode

# Or switch back to Emacs mode permanently:
set -o emacs

# Add to ~/.bashrc:
echo "set -o emacs" >> ~/.bashrc

History Not Saving

Problem: Command history not persisted between sessions.

Solution:

# Check HISTFILE is set
echo $HISTFILE

# Check history is enabled
set -o | grep history

# Enable history:
set -o history

# Add to ~/.bashrc:
export HISTFILE=~/.bash_history
export HISTSIZE=10000
export HISTFILESIZE=20000

Completion Not Working

Problem: Tab completion doesn't work or incomplete.

Solution:

# Install bash-completion (Debian/Ubuntu)
sudo apt-get install bash-completion

# Install bash-completion (macOS)
brew install bash-completion@2

# Source in ~/.bashrc:
[[ -r "/usr/local/etc/profile.d/bash_completion.sh" ]] && . "/usr/local/etc/profile.d/bash_completion.sh"

# Check programmable completion is enabled:
shopt -p progcomp

Inputrc Changes Not Applied

Problem: Changes to ~/.inputrc don't take effect.

Solution:

# Reload inputrc without restarting shell
bind -f ~/.inputrc

# Or restart shell:
exec bash

# Check if changes were applied:
bind -v | grep setting-name

Special Characters Not Inserting

Problem: Need to insert literal control characters.

Solution:

# Use quoted-insert (Ctrl-v)
Ctrl-v Tab      # Insert literal tab
Ctrl-v Ctrl-a   # Insert literal ^A

# In Vi mode (command mode):
# Press Ctrl-v then the character

Configuration Examples

Minimal ~/.inputrc

# Basic configuration
set editing-mode emacs
set bell-style none
set completion-ignore-case on
set show-all-if-ambiguous on

# Better history search
"\e[A": history-search-backward
"\e[B": history-search-forward

Advanced ~/.inputrc

# Editing mode
set editing-mode emacs
set bell-style none

# Completion
set completion-ignore-case on
set show-all-if-ambiguous on
set visible-stats on
set mark-symlinked-directories on
set colored-stats on
set colored-completion-prefix on
set completion-map-case on
set skip-completed-text on

# History
set history-preserve-point on
set revert-all-at-newline on

# Key bindings
"\e[A": history-search-backward
"\e[B": history-search-forward
"\C-p": history-search-backward
"\C-n": history-search-forward

# Macros
"\C-xg": "git status\n"
"\C-xl": "ls -lah\n"
"\C-xh": "cd ~\n"

# Application-specific
$if Bash
  Space: magic-space
  "\C-x\C-e": edit-and-execute-command
$endif

$if Python
  "\C-l": clear-screen
$endif

Vi Mode Configuration

# ~/.inputrc
set editing-mode vi
set keymap vi-command

# Show mode indicator
set show-mode-in-prompt on
set vi-ins-mode-string "\1\e[6 q\2"
set vi-cmd-mode-string "\1\e[2 q\2"

# Use Emacs-style completion in insert mode
set keymap vi-insert
"\C-p": history-search-backward
"\C-n": history-search-forward
"\C-a": beginning-of-line
"\C-e": end-of-line

Integration Examples

Python REPL

# ~/.inputrc
$if Python
  set editing-mode emacs
  set completion-ignore-case on
  "\C-p": history-search-backward
  "\C-n": history-search-forward
$endif

MySQL Client

# ~/.inputrc
$if mysql
  set completion-ignore-case on
  set show-all-if-ambiguous on
  "\C-p": history-search-backward
  "\C-n": history-search-forward
$endif

GDB Debugger

# ~/.inputrc
$if gdb
  set editing-mode emacs
  "\C-p": history-search-backward
  "\C-n": history-search-forward
$endif

Also see

GNU Readline Cheatsheet - NexusCS