Die Vervollständigung des Befehls (zusammen mit anderen Dingen) wird über die Bash Readline-Vervollständigung abgewickelt . Dies funktioniert auf einer etwas niedrigeren Ebene als die übliche "programmierbare Vervollständigung" (die nur aufgerufen wird, wenn der Befehl identifiziert wurde und die beiden oben angegebenen Sonderfälle).
Update: Die neue Version von bash-5.0 (Januar 2019) ergänzt complete -I
genau dieses Problem.
Die relevanten Readline-Befehle sind:
complete (TAB)
Attempt to perform completion on the text before point. Bash
attempts completion treating the text as a variable (if the text
begins with $), username (if the text begins with ~), hostname
(if the text begins with @), or command (including aliases and
functions) in turn. If none of these produces a match, filename
completion is attempted.
complete-command (M-!)
Attempt completion on the text before point, treating it as a
command name. Command completion attempts to match the text
against aliases, reserved words, shell functions, shell
builtins, and finally executable filenames, in that order.
In ähnlicher Weise wie üblich complete -F
kann ein Teil davon durch Verwendung von an eine Funktion übergeben werden bind -x
.
function _complete0 () {
local -a _cmds
local -A _seen
local _path=$PATH _ii _xx _cc _cmd _short
local _aa=( ${READLINE_LINE} )
if [[ -f ~/.complete.d/"${_aa[0]}" && -x ~/.complete.d/"${_aa[0]}" ]]; then
## user-provided hook
_cmds=( $( ~/.complete.d/"${_aa[0]}" ) )
elif [[ -x ~/.complete.d/DEFAULT ]]; then
_cmds=( $( ~/.complete.d/DEFAULT ) )
else
## compgen -c for default "command" complete
_cmds=( $(PATH=$_path compgen -o bashdefault -o default -c ${_aa[0]}) )
fi
## remove duplicates, cache shortest name
_short="${_cmds[0]}"
_cc=${#_cmds[*]} # NB removing indexes inside loop
for (( _ii=0 ; _ii<$_cc ; _ii++ )); do
_cmd=${_cmds[$_ii]}
[[ -n "${_seen[$_cmd]}" ]] && unset _cmds[$_ii]
_seen[$_cmd]+=1
(( ${#_short} > ${#_cmd} )) && _short="$_cmd"
done
_cmds=( "${_cmds[@]}" ) ## recompute contiguous index
## find common prefix
declare -a _prefix=()
for (( _xx=0; _xx<${#_short}; _xx++ )); do
_prev=${_cmds[0]}
for (( _ii=0 ; _ii<${#_cmds[*]} ; _ii++ )); do
_cmd=${_cmds[$_ii]}
[[ "${_cmd:$_xx:1}" != "${_prev:$_xx:1}" ]] && break
_prev=$_cmd
done
[[ $_ii -eq ${#_cmds[*]} ]] && _prefix[$_xx]="${_cmd:$_xx:1}"
done
printf -v _short "%s" "${_prefix[@]}" # flatten
## emulate completion list of matches
if [[ ${#_cmds[*]} -gt 1 ]]; then
for (( _ii=0 ; _ii<${#_cmds[*]} ; _ii++ )); do
_cmd=${_cmds[$_ii]}
[[ -n "${_seen[$_cmds]}" ]] && printf "%-12s " "$_cmd"
done | sort | fmt -w $((COLUMNS-8)) | column -tx
# fill in shortest match (prefix)
printf -v READLINE_LINE "%s" "$_short"
READLINE_POINT=${#READLINE_LINE}
fi
## exactly one match
if [[ ${#_cmds[*]} -eq 1 ]]; then
_aa[0]="${_cmds[0]}"
printf -v READLINE_LINE "%s " "${_aa[@]}"
READLINE_POINT=${#READLINE_LINE}
else
: # nop
fi
}
bind -x '"\C-i":_complete0'
Dies aktiviert Ihre eigenen Befehle oder Präfixzeichenfolgen ~/.complete.d/
. ZB wenn Sie eine ausführbare Datei erstellen ~/.complete.d/loc
mit:
#!/bin/bash
echo localc
Dies wird (ungefähr) das tun, was Sie erwarten.
Die obige Funktion emuliert das normale Verhalten beim Beenden von Bash-Befehlen, ist jedoch unvollkommen (insbesondere das zweifelhafte Vorgehen sort | fmt | column
beim Anzeigen einer Liste von Übereinstimmungen).
Ein nicht triviales Problem, bei dem nur eine Funktion zum Ersetzen der Bindung an die Hauptfunktion verwendet werden complete
kann (standardmäßig mit TAB aufgerufen).
Dieser Ansatz würde gut mit einer anderen Schlüsselbindung funktionieren, die nur für die Vervollständigung von benutzerdefinierten Befehlen verwendet wird, implementiert jedoch einfach nicht die Logik für die vollständige Vervollständigung danach (z. B. spätere Wörter in der Befehlszeile). Dazu müsste man die Befehlszeile analysieren, sich mit der Cursorposition und anderen kniffligen Dingen befassen, die in einem Shell-Skript wahrscheinlich nicht berücksichtigt werden sollten ...
loc
zu erstellenlocalc
? Ich schlage Alternativen vor, da ich nach einiger Zeit beim Graben und Suchen keine Möglichkeit gefunden habe, die Bash-Vervollständigung auf diese Weise anzupassen. Möglicherweise ist dies nicht möglich.