Bash Completion in eigenen Skripten einsetzen

Aus Laub-Home Wiki

Die Bash Completion erlaubt es durch das betätigen der Tab-Taste Befehle, Dateipfade und Optionen zu vervollständigen um unnötiges Tippen zu ersparen. In diesem Artikel wird gezeigt, wie die Vervollständigung von Optionen für eigene Skripte genutzt werden kann.
Voraussetzung ist das bash-completion installiert ist:

apt install bash-completion

Szenario

Nehmen wir an wir haben ein Skript bash_completion_test.sh und wollen, dass die Optionen hier, haus und katze vervollständigt werden.

Statische Optionen

Es wird nun eine neue Datei mit dem Namen des Skriptes in /etc/bash_completion.d angelegt: /etc/bash_completion.d/bash_completion_test.sh

_bash_completion_test() 
{
    local cur prev opts
    COMPREPLY=()
    cur="${COMP_WORDS[COMP_CWORD]}"
    prev="${COMP_WORDS[COMP_CWORD-1]}"
    opts="hier haus katze"
    COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
    return 0
}
complete -F _bash_completion_test bash_completion_test.sh

Dabei sollte beachtet werden dass

  1. der Name der Bash-Funktion der gleiche seien sollte wie der Name des Skriptes, dass vervollständigt werden soll und mit einem Unterstrich beginnt (da Punkte nicht erlaubt sind wurde die Endung .sh weggelassen)
  2. in der Variable opts alle möglichen Werte für die Vervollständigung stehen
  3. hinter complete -F (letzte Zeile) der Name der Bash-Funktion und direkt dahinter der Name des Skriptes eingetragen wird

Nach einem erneuten sourcen der Datei /etc/bash_completion bzw. einem Re-Login sollte nun die Vervollständigung funktionieren.

root@test:~# bash_completion_test.sh          # [TAB][TAB]
haus   hier   katze
root@test:~# bash_completion_test.sh h        # [TAB][TAB]
haus   hier
root@test:~# bash_completion_test.sh ha       # [TAB]
root@test:~# bash_completion_test.sh haus

Dynamische Optionen

Der Inhalt der Variable opts muss nicht statisch angegeben sondern kann auch Skript-typisch dynamisch erzeugt werden. Folgendes würde z.B. als mögliche Werte für die Vervollständigung alle Ordner und Dateien des Verzeichnisses /etc festlegen:

opts="$(ls /etc)"

Es sollte beachtet werden, dass die Ausführung der Befehle relativ schnell gehen und nicht mehrere Sekunden dauern, da diese Verzögerungen direkt bei der Vervollständigung weitergegeben werden.

Vervollständigung von Unteroptionen

Will man abhängig von der vorher eingegebenen Option andere Vervollständigungen nutzen kann folgendes verwendet werden:

_bash_completion_test() 
{
    local cur prev opts base
    COMPREPLY=()
    cur="${COMP_WORDS[COMP_CWORD]}"
    prev="${COMP_WORDS[COMP_CWORD-1]}"

    opts="hier haus katze"

    ### erweiterte Vervollstaendigung ###
    case "${prev}" in
	haus)
	    local stockwerk="dachgeschoss erdgeschoss keller"
	    COMPREPLY=( $(compgen -W "${stockwerk}" -- ${cur}) )
            return 0
            ;;
        katze)
	    local koerperteile="pfote auge schwanz"
	    COMPREPLY=( $(compgen -W "${koerperteile}" -- ${cur}) )
            return 0
            ;;
        *)
        ;;
    esac

    COMPREPLY=($(compgen -W "${opts}" -- ${cur}))  
    return 0
}
complete -F _bash_completion_test bash_completion_test.sh

Mit der Variable prev wird das vorherige Wort kontrolliert und über ein Case-Statement abhängig von dem Ergebnis andere Vervollständigungen gesetzt. Dazu wurden jeweils neue lokale Variablen mit den dazugehörigen Werten erstellt. Diese neuen Variablen (hier stockwerk und koerperteil) werden bei der Vervollständigung (compgen Befehl) anstelle von opts benutzt.

Das angegebene Skript würde zu folgendem Ergebnis führen:

root@test:~# bash_completion_test.sh          # [TAB][TAB]
haus   hier   katze
root@test:~# bash_completion_test.sh h        # [TAB][TAB]
haus   hier
root@test:~# bash_completion_test.sh ha       # [TAB]
root@test:~# bash_completion_test.sh haus     # [TAB][TAB]
dachgeschoss   erdgeschoss   keller
root@test:~# bash_completion_test.sh katze    # [TAB][TAB]
auge     pfote    schwanz
root@test:~# bash_completion_test.sh hier    # [TAB][TAB]
haus   hier   katze

Quellen