Shellkonfiguration – Übersicht

Editieren der Kommandozeile (bash / Readline)

Das Beherrschen der wichtigsten Funktionen zum Editieren der Kommandozeile ist nicht nur ein gigantischer Produktivitätsgewinn, sondern erspart einem auch die potentiell sehr nervtötenden Alternativen. Es ist vergleichbar mit dem Wechsel von nano zu vim (Readline hat sogar einen vim-Modus).

Strenggenommen...

Die Readline-Dokumentation benutzt nicht die Bezeichnung Alt, sondern Meta. Typischerweise ist Alt als Meta-Taste definiert. Alternativ kann man Esc nutzen (dann ist sogar egal, ob man die Esc-Taste noch gedrückt hält oder vor dem "zu meta-isierenden" Zeichen).

Der (mutmaßlich) besseren Lesbarkeit / Verständlichkeit halber wird im folgenden dennoch Alt verwendet.

shell history

Grundsätzlich ist die shell history immens nützlich; das gilt aber nicht für alle Varianten des Zugangs zu dieser Funktion für alle Nutzer. Zu den für mich wichtigsten Funktionen gehört die Bewegung durch die shell history mit den Pfeiltasten nach oben und nach unten (aus Sicht der Shell sind die Pfeiltasten normalerweise die Zeichenfolge Esc-[-A bzw. Esc-[-B):

ec:0   15:57:04  hl@notebook:~
start cmd: bind -p | grep -e previous-history -e next-history
"\C-n": next-history
"\eOB": next-history      # Pfeiltaste nach unten (im Applikations-Modus)
"\e[B": next-history      # Pfeiltaste nach unten (im normalen Terminal-Modus)
"\C-p": previous-history
"\eOA": previous-history  # Pfeiltaste nach oben (im Applikations-Modus)
"\e[A": previous-history  # Pfeiltaste nach oben (im normalen Terminal-Modus)

ec:0   15:57:06  hl@notebook:~
start cmd:

Dieselbe Funktion kann also über unterschiedliche Tastatureingaben aufgerufen werden. Der obige Shell-Code zeigt, wie man herausfinden kann, wie eine Readline-Funktion heißt (wenn man weiß, über welche Tastatureingabe sie ausgelöst wird) und welche Tastatureingabe eine Readline-Funktion auslöst (wenn man weiß, wie sie heißt). Die Funktion für Pfeiltaste nach unten bekommt man mit bind -p | grep -F '"\e[B"' Die Option -F ist wichtig, weil sie dafür sorgt, dass das Argument als einfacher Text verstanden wird und nicht als regulärer Ausdruck. Wenn man nicht weiß, wie die Shell eine Taste (bzw. ein Zeichen) sieht, kann man sich das mit z.B. od oder cat anzeigen lassen. In diesem Fall bekommt man dann nicht die Ausgabe \e[B, sondern ^[[B, weil Esc vom Terminal als ^[ angezeigt wird.

Konfiguration der history

Das bash-builtin history zeigt die gesamte history an (und ermöglicht deren Manipulation). Mehrere Shell-Variablen steuern das Verhalten der history:

HISTCONTROL

Durch Doppelpunkt getrennte Werte: ignorespace:ignoredups:ignoreboth:erasedups Empfehlung: ignoreboth:erasedups

ignorespace verhindert, dass Kommandozeilen, die mit einem Leerzeichen beginnen, der history hinzugefügt werden. Das ist etwa dann sinnvoll, wenn die Kommandozeile ein Passwort oder andere vertrauliche Daten enthält.

erasedups sorgt dafür, dass Kommandozeilen, die der history oder der history-Datei hinzugefügt werden, nur ein Mal darin enthalten sind.

HISTFILE Die Datei, in die (ggf.) beim ordentlichen die aktuelle history geschrieben wird (mit oder ohne Zeitstempel, siehe HISTTIMEFORMAT). Der Standardpfad ist ˜/.bash_history
HISTSIZE Die Anzahl der Kommandozeilen, die (maximal) in der RAM history gespeichert werden. Standardmäßig 500.
HISTFILESIZE Die Anzahl der Kommandozeilen, die (maximal) in der RAM history gespeichert werden. Standardmäßig 500 (der Wert von $HISTSIZE).
HISTIGNORE Durch Doppelpunkt getrennte globbing patterns. Kommandozeilen, die auf eins der patterns passen, werden der history nicht hinzugefügt.
HISTTIMEFORMAT Wenn diese Variable gesetzt ist (auch wenn sie leer ist), werden in die history-Datei nicht nur die Kommandozeilen geschrieben, sondern auch die zugehörigen Zeitstempel (in der RAM-history werden sie immer gespeichert).
hl@notebook:~ $ HISTTIMEFORMAT='%Y-%m-%d %H:%M:%S   '
hl@notebook:~ $ history
    3  2024-08-19 00:31:23   echo a
    4  2024-08-19 00:31:25   echo b
    5  2024-08-19 00:31:27   echo c

Pro-User shell history in der root-Shell

Wenn es mehrere Admins auf einem System gibt, mag es sinnvoll sein, deren Aktivitäten in einer root-Shell voneinander zu trennen. Dafür bieten sich einerseite getrennte screen- oder tmux-Sessions an, andererseits eine eigene shell history für jeden User. Es bietet sich an, an den üblichen Pfad der history-Datei (˜/.bash_history) die UID oder den Accountnamen des Users, der sich root-Rechte verschafft hat, anzuhängen.

Der beste Weg dafür, jedenfalls auf Systemen, auf denen pam_loginuid aktiv ist, ist /proc/self/loginuid.

# use the login UID as suffix
if [ "$EUID" -eq 0 ]; then
    if [ -f /proc/self/loginuid ]; then
        loginuid="$(< /proc/self/loginuid )"
        HISTFILE="${HOME}/.bash_history.${loginuid}"
        unset loginuid
    fi
fi

# use the login name as suffix
if [ "$EUID" -eq 0 ]; then
    if [ -f /proc/self/loginuid ]; then
        loginuid="$(< /proc/self/loginuid )"
        HISTFILE="${HOME}/.bash_history.${loginuid}"
        if login_name="$( id -un "$loginuid" 2>/dev/null )" && [ -n "$login_name" ]; then
            HISTFILE="${HOME}/.bash_history.${login_name}"
            unset login_name
        fi
        unset loginuid
    fi
fi

Speicher- und Filterstrategien

Typischerweise dürfte sinnvoller sein, jedes Kommando nur ein Mal in der history zu haben (also erasedups zu verwenden).

Dedizierte history-Datei für eine Aktion

Eine Ausnahme ist der Fall, in dem man sauber dokumentieren möchte, was auf einem System (in einem bestimmten Zeitraum) gemacht wurde. Es mag sinnvoll sein, dafür eine gesondere history-Datei zu setzen. Insbesondere mögen gesonderte history-Dateien sinnvoll sein, wenn man in mehreren Shells arbeitet, um die Probleme beim Zusammenführen zu vermeiden. Da dies nur die Eingaben erfasst, mag man zusätzlich script (und dann scriptreplay) verwenden.

Eine solche dedizierte Datei für die shell history könnte eine ähnliche Aktion in der Zukunft erleichtern, indem man eine Kopie dieser Datei in die neue Shell-Sitzung lädt (history -r).

create_event_shell_history () {
        local hist_file_path
        read -p 'Enter the name of the shell event (no "/"): ' shell_event_name
        if [ -z "${shell_event_name}" ] || [[ $shell_event_name =~ / ]]; then
                printf '%s\n' 'ERROR: invalid input; aborting'
                return 1
        fi
        tty="$( tty )"
        tty="${tty#/}"
        tty="${tty//\//-}"
        hist_file_path="${HOME}/.bash_history.${shell_event_name}.${tty}"
        if [ -f "${hist_file_path}" ]; then
                printf '%s\n' "ERROR: The history file '${hist_file_path}' already exists; aborting"
                return 1
        fi
        printf '%s\n' "INFO: Using the file '${hist_file_path}' for the shell history; you can write it with 'history -w' (again and again)"
        HISTFILE="${hist_file_path}"
        HISTSIZE=10000
        HISTFILESIZE=10000
        HISTCONTROL=
        HISTTIMEFORMAT='%Y-%m-%d %H:%M:%S   '
        # clear history
        history -c
        # create history file
        history -w
}

Einfügen des letzten Arguments der vorherigen Kommandozeile

Eine weitere sehr häufig von mir genutzte Funktion ist das Einfügen des letzten Arguments der vorherigen Kommandozeile. Typische Fälle:

Es gibt (mindestens) zwei "unkritische" Möglichkeiten, das letzte Argument der vorherigen Kommandozeile in die aktuelle einzufügen (auch mehrfach):

Die Alt-.-Variante ist in mehrfacher Hinsicht überlegen:

Die allgemeine Variante (beliebiges Wort der vorherigen Kommandozeile) ist die Kombination der readline-Funktion digit-argument mit yank-nth-arg. Die zuerst angegebene Ziffer ist der Index des Wortes der vorherigen Kommandozeile, angefangen mit null. Null ist das Kommandowort, Eins das erste Argument. digit-argument wird standardmäßig aufgerufen mit Alt-n, wobei n für die jeweilige Ziffer steht.

history expansion

Neben den oben genannten Readline key bindings gibt es das mächtigere bash-Feature history expansion. Ich konnte mich damit nie so recht anfreunden. Ich nutze es zu selten und habe deshalb zumeist die Syntax-Details vergessen, wenn ich es mal gebrauchen könnte. Zumeist ist (oder zumindest erscheint) es schlicht sehr viel schneller,

Die grundsätzliche Vorgehensweise ist, dass der erste Teil des history expansion-Ausdrucks die Kommandozeile auswählt und der zweite Teil ein oder mehrere Worte daraus. Wenn keine Worte ausgewählt werden, wird die gesamte Zeile verwendet.

Eingeleitet wird der Ausdruck mit dem history expansion character, standardmäßig ein Ausrufezeichen. Doppelte Ausrufezeichen referenzieren die vorherige Kommandozeile (!! entspricht !-1).

Wenn man history expansion nutzen möchte (standardmäßig aktiv, kann mit set +H / set -H (de-)aktiviert werden), erscheinen mir zwei Shell-Einstellungen sehr nützlich:

Suche in der Shell history

Die Suche in der Shell history gehört für mich zu den wichtigsten Shell-Features überhaupt. Ich nutze es ständig, und es spart immens viel Zeit (und Nerven).

Es gibt mindestens vier Möglichkeiten, eine frühere Kommandozeile zu suchen:

Work-around zur leichten Adressierung in der history (Umgebungsvariablen)

Eine Möglichkeit, schnell und in leicht merkbarer Weise viele Einträge in der history zu adressieren, ergibt sich aus dem "Missbrauch" von Kommandozeilen-Umgebungsvariablen. Man kann einfach Variablen kreieren, die nicht benötigt werden, aber deren Namen sich leicht merken und schnell tippen lassen:

x_cd_a= cd /langer/pfad
x_foo= command with many parameters

Die Einträge lassen sich dann leicht über x_fooPgUp oder !?x_fooEnter aufrufen. Man sollte dann aber ggf. darauf achten, das Kommando nicht zu editieren (ohne die Adressierungs-Variable zu löschen oder umzubenennen).

Neben der besseren Adressierbarkeit kann man dies z.B. auch dafür nutzen, unübersichtliche Kommandos leicht auseinanderhalten zu können.

Es ist allerdings grundsätzlich zu überlegen, ob es mehr Sinn ergibt, die Kommandozeile in eine Funktion oder einen Alias zu packen. Damit vermeidet man versehentliches Editieren. Das kann sehr störend werden, wenn man die Kommandozeile gelegentlich editieren muss. In dem Fall mag ein Alias die bessere Lösung sein, weil man den mit (z.B., s.u.) der Readline-Funktion shell-expand-line auflösen und dann risikolos editieren kann: x_cd_aCtrl-Alt-e führt zu folgendem Text in der Kommandozeile (den man dann vor der Ausführung editieren kann): cd /langer/pfad

"Copy & Paste"

Zwei der von mir meistgenutzten Readline-Funktionen sind das wortweise Löschen von Teilen der Kommandozeile und das Einfügen des letzten oder eines früheren gelöschten Textes. Viele dieser Funktionen (diejenigen, die sich sinnvoll mehrfach unmittelbar hintereinander ausführen lassen) können mit einem numerischen Argument versehen werden (wie bei yank-nth-arg), indem digit-argument vorher aufgerufen wird (für Zahlen größer Neun mehrfach). Der Ringspeicher, der die gelöschten Texte aufnimmt, wird kill ring genannt.

Im kill ring werden nur diejenigen Löschaktionen gespeichert, die nicht mittels Backspace / Ctrl-h oder Del nur ein einzelnes Zeichen löschen, also etwa

Wenn unmittelbar hintereinander Readline-Funktionen (dieselbe oder unterschiedliche) ausgeführt werden, die Text in den kill ring kopieren, dann werden die betroffenen Texte zu einem einzigen Element im kill ring zusammengefügt.

Dies sind alles Beispiele für "cut & paste", nicht "copy & paste". Es gibt analoge Readline-Funktionen, die in den kill ring kopieren, ohne zu löschen, aber die benutze ich nie. Zu löschen und mit einer simplen Tastenkombination sofort wiedereinzufügen, erfüllt denselben Zweck. Sich doppelt so viele Tastenkombinationen zu merken, um dies zu vermeiden, erscheint wenig attraktiv. Das scheint eine verbreitete Haltung zu sein, denn keine dieser Funktionen hat eine standardmäßige Tastenkombination...

Paste

Das Einfügen des aktiven kill-ring-Elements erfolgt mit Ctrl-y (yank).

Ein älteres Element des kill ring kann man einfügen, indem man zuerst mittels yank das aktuelle Element einfügt und dann mit yank-pop (standardmäßig Alt-y) durch den kill ring rotiert; dadurch wird das zuletzt eingefügte Element durch das nächstältere (bzw., am Ende des kill ring, durch das neuste) ersetzt.

Undo – Änderungen an einer Kommandozeile rückgängig machen

Mit der Funktion undo (standardmäßig Ctrl-_) kann man die Änderungen an der Kommandozeile einzeln rückgängig machen. Dabei werden alle ununterbrochenen Texteingaben ohne (effektive) Änderung der Cursorposition als eine einzige Änderung behandelt.

Mit der Funktion revert-line (standardmäßig Alt-r) wird die Kommandozeile in ihren Ursprungszustand zurückversetzt (wie mehrfaches Ausführen von undo). Für eine neue Kommandozeile bedeutet das, dass sie gelöscht wird. Sinnvoll ist das also in erster Linie, wenn man eine Kommandozeile aus der history editiert.

Cursorbewegungen

Man möchte nicht mit vielen Einzelschritten durch die Kommandozeile laufen, um Änderungen vorzunehmen. Das gilt insbesondere für langsame und / oder unzuverlässige Netzwerkverbindungen.

Es gibt mehrere sehr nützliche Readline-Funktionen, um den Cursor schnell und gezielt an die richtige Stelle zu bekommen. Viele dieser Funktionen (diejenigen, die sich sinnvoll mehrfach unmittelbar hintereinander ausführen lassen) können mit einem numerischen Argument versehen werden (wie bei yank-nth-arg), indem digit-argument vorher aufgerufen wird (für Zahlen größer Neun mehrfach):

Weitere interessante Readline-Funktionen

Einfügen / Überschreiben

overwrite-mode (bei mir Ins) schaltet um zwischen den Modi Einfügen und Überschreiben. Diese Einstellung wird nach der Ausführung der Kommandozeile automatisch auf Einfügen zurückgesetzt.

Vervollständigung

Die mit großem Abstand wichtigste Funktion im Zusammenhang mit Vervollständigung ist complete. Diese Funktion aktiviert das Shell-Feature Programmable Completion, das natürlich viel mächtiger ist als die eher oberflächlichen Readline-Vervollständigungen.

Es gibt aber gelegentlich Situationen, in denen Programmable Completion nicht greift, aber man trotzdem einen Pfad, Benutzerlogin, Hostnamen (siehe die bash-Variable $HOSTFILE) oder einen Variablennamen vervollständigt haben will. Es gibt zwei Varianten der Vervollständigung:

Die verfügbaren Vervollständigungs-Funktionen sind:

Auflösung von Variablen, Aliasen, history-expansion-Ausdrücken und anderen Ersetzungen

Readline kann Pfade von Homeverzeichnissen (tilde expansion), Aliase und history-expansion-Ausdrücke auflösen; ebenso Variablen und alle Arten von Ersetzungen: command substitution, arithmetic expansion, pathname expansion (globbing) und process substitution. Allerdings werden doppelte Anführungszeichen dabei gelöscht, so dass die Bedeutung der Kommandozeile sich dadurch ändern kann.

Der Unterschied zwischen pathname expansion (globbing) und den anderen Funktionen ist, dass die anderen sich kollektiv für die gesamte Kommandozeile behandeln lassen. pathname expansion kann nur pro Ausdruck ausgeführt werden.

Die verfügbaren Auflösungs-Funktionen sind:

Markierung / Region

Readline bietet die Möglichkeit, mit set-mark (standardmäßig Ctrl-@ oder Alt-Space) innerhalb einer Kommandozeile eine Markierung zu setzen. Der Bereich von der Markierung bis zur Cursorposition wird als Region bezeichnet. Die Region inkludiert die linke Grenze, aber nicht die rechte (unabhängig davon, ob die Markierung die linke oder rechte Grenze ist). Die Funktion exchange-point-and-mark (standardmäßig Ctrl-x Ctrl-x) vertauscht die Positionen von Cursor und Markierung und markiert die Region farblich; zweifaches Ausführen erhält die ursprünglichen Positionen und die farbliche Markierung. Die Region kann gelöscht (und dadurch in den kill ring kopiert) oder direkt in den kill ring kopiert werden. Löschen erfolgt über die Funktion kill-region (bei mir Shift-Del). Kopieren ist am einfachsten (wie sonst auch) durch Löschen und sofortiges Wiedereinfügen (Ctrl-y).

Dies ist nur selten nötig. Vorteile gegenüber den normalen Löschfunktionen sind,

Bearbeitung der Kommandozeile im Editor

Wenn eine Kommandozeile zu komplex und / oder kompliziert ist, ist es oftmals sinnvoller, sie in eine Scriptdatei zu packen, weil der Editor mehr Möglichkeiten bietet als Readline und die Formatierung den Code sehr viel lesbarer machen kann.

Es gibt eine Zwischenlösung auf halber Strecke zwischen Kommandozeile und Scriptdatei. edit-and-execute-command (standardmäßig Ctrl-x -e) schreibt die (ggf. noch leere) Kommandozeile in eine Datei und öffnet diese mit dem in der Umgebungs-Variable $VISUAL oder $EDITOR festgelegten Editor (oder mit emacs, falls beide leer / ungültig sind). Nach dem Speichern der Datei und dem Beenden des Editors wird der Inhalt der Datei als Kommandozeile ausgeführt.

Groß- / Kleinschreibung

upcase-word (standardmäßig Alt-u), downcase-word (standardmäßig Alt-l) und capitalize-word (standardmäßig Alt-c) ändern (ggf.) die Groß- / Kleinschreibung des Worts (oder Wortteils) rechts vom Cursor.

Mehrfache Eingabe von Zeichen

Die schon mehrfach erwähnte Funktion digit-argument erlaubt auch die wiederholte Eingabe eines Zeichens. Praktisch, wenn man genau eine bestimmte, größere Anzahl von Zeichen (und sei es zum Überschreiben) braucht: Alt-6 Alt-4 x

xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Macros: Einfügen von statischem Text

Die Readline-Funktionen werden durch Kommandozeilen der Art bind '"\C-@":set-mark' an Tasten(kombinationen) gebunden. Mit der Form bind '"\C-t":"statischer Text"' kann eine feste Zeichenfolge eingefügt werden.

Eigene Onlinehilfe

Das große praktische Problem mit den vielen Tastenkombinationen ist natürlich: Wenn man sie nicht häufig verwendet, ist es schwierig, sie sich zu merken. Dieses Problem lässt sich leicht entschärfen, indem man sich eine kleine Ausgabe der als relevant empfundenen Funktionen mit der jeweiligen Tastenkombination generiert.

Das kann man mit einer Shellfunktion machen

rlf () {
printf '%s\n' 'possible-completions (M-?)
complete-filename (M-/)
complete-username (M-˜)
complete-variable (M-$)
complete-hostname (M-@)
tilde-expand (M-&)
history-expand-line (M-ˆ)
shell-expand-line (M-C-e)'
}

aber auch mit einer Readline-Tastenkombination (hier beispielhaft Ctrl-Alt-h, aber F1 bietet sich an, wenn die Taste nicht vor der Shell abgefangen wird), die einfach nur einen Text ausgibt (als auskommentiertes Kommando); was besser ist, sei mal dahingestellt:

bind '"\e\C-h":": \"possible-completions (M-?)
# complete-filename (M-/)
# complete-username (M-˜)
# complete-variable (M-$)
# complete-hostname (M-@)
# tilde-expand (M-&)
# history-expand-line (M-ˆ)
# shell-expand-line (M-C-e)\"
"'

Da man diese Information zumeist während der Bearbeitung einer Kommandozeile benötigt, bietet es sich an, die Bearbeitung zu unterbrechen, indem man (mit Ctrl-a) an den Anfang springt, dort ein Kommentarzeichen (#) einfügt und die Kommandozeile dann "ausführt". Dann kann man sich die Onlinehilfe ausgeben lassen und sich die noch unfertige Kommandozeile aus der history holen.

dynamische Macros

Als Ergänzung zu den statischen Macros bietet Readline die Möglichkeit, (leider nur) eine Eingabe aufzuzeichnen (inklusive Steuerzeichen). Vorteile gegenüber der Nutzung des kill ring:

Die Macro-Funktionen:

Readline-Variablen

Das Verhalten von Readline kann durch einige Readline-Variablen (das sind keine Shell-Variablen) gesteuert werden. Wenn man in der man page von bash nach Readline Variables sucht, landet man direkt beim richtigen Abschnitt. Ich hatte nur bei einer das Bedürfnis, die zu ändern:

bind 'set show-all-if-ambiguous on' sorgt dafür, dass man sich in dem häufigen Fall, dass es bei tab completion mehrere Möglichkeiten gibt, eine Eingabe von Tab sparen kann: Nach der ersten Eingabe werden die Möglichkeiten sofort angezeigt.

Readline konfigurieren

Es gibt zwei Möglichkeiten, die Readline-Konfiguration vorzunehmen:

Ich nutze Readline (bewusst) nur in bash, deshalb nutze ich die zweite Variante. In einer meiner bash-Konfigurationsdateien findet sich dieser Codeblock (der nur in interaktiven Shells ausgeführt werden soll):

if [[ $- =~ i ]]; then

    # BEGIN: search
    # <PgUp> :   non-incremental search for the same beginning of a command line
    bind '"\e[5~":history-search-backward'
    # <PgDown> : non-incremental search for the same beginning of a command line
    bind '"\e[6~":history-search-forward'
    # <Ctrl>-F : ^S is usually caught by the terminal so changed to ^F
    bind '"\C-f":forward-search-history'
    # <Ctrl>-R
    bind '"\C-r":reverse-search-history'
    # END:   search

    # BEGIN: delete
    # <Shift>-<Del>
    bind '"\e[3;2~":kill-region'
    # <Ctrl>-<Del> : words limited by unquoted metacharacter
    bind '"\e[3;5~":shell-backward-kill-word'
    # <Alt>-<Del> :  words limited by unquoted metacharacter
    bind '"\e[3;3~":shell-kill-word'
    # <Shift>-<Ctrl>-<Del> : delete path elements from right to left (until slash or blank)
    bind '"\e[3;6~":unix-filename-rubout'
    # END:   delete

    # BEGIN: move
    # <Ctrl>-<arrow left> :  words limited by non-alphanumeric character
    bind '"\e[1;5D":backward-word'
    # <Ctrl>-<arrow right> : words limited by non-alphanumeric character
    bind '"\e[1;5C":forward-word'
    # <Alt>-<arrow left> :  words limited by unquoted metacharacter
    bind '"\e[1;3D":shell-backward-word'
    # <Alt>-<arrow right> : words limited by unquoted metacharacter
    bind '"\e[1;3C":shell-forward-word'
    # <Ctrl>-<arrow up> :   with a multi-line command line: go straight up one line
    bind '"\e[1;5A":previous-screen-line'
    # <Ctrl>-<arrow down> : with a multi-line command line: go straight down one line
    bind '"\e[1;5B":next-screen-line'
    # END:   move

    # BEGIN: region
    # <Ctrl>-^ <Space>
    bind '"\C-^ ":set-mark'
    # <Ctrl>-^ x
    bind '"\C-^x":exchange-point-and-mark'
    # END:   region

    # BEGIN: dynamic macro
    # <Ctrl>-^ <Ctrl>-m s
    bind '"\C-^\C-ms":start-kbd-macro'
    # <Ctrl>-^ <Ctrl>-m e
    bind '"\C-^\C-me":end-kbd-macro'
    # <Ctrl>-^ <Ctrl>-m c
    bind '"\C-^\C-mc":call-last-kbd-macro'
    # <Ctrl>-^ Ctrl>-m p
    bind '"\C-^\C-mp":print-last-kbd-macro'
    # END:   dynamic macro

    # other
    # insert key: switch between insert and overwrite modes
    bind '"\e[2~":overwrite-mode'
    # <Ctrl>-^ l
    bind '"\C-^l":glob-list-expansions'
    # <Ctrl>-^ e
    bind '"\C-^e":edit-and-execute-command'
    # <F1> "online help"
    bind '"\eOP":": \"
# set-mark (C-^ SPACE)
# exchange-point-and-mark (C-^ x)
# kill-region (<Shift>-<Del>)
# complete-filename (M-/)
# complete-username (M-˜)
# complete-variable (M-$)
# complete-hostname (M-@)
# tilde-expand (M-&)
# history-expand-line (M-ˆ)
# glob-list-expansions (C-^ l)
# shell-expand-line (M-C-e)
# edit-and-execute-command (C-^ e)\"
"'

    # BEGIN: set readline variables
    bind 'set show-all-if-ambiguous on'
    # END:   set readline variables
fi