명령 완료 (다른 것들과 함께)는 bash readline complete를 통해 처리됩니다 . 이것은 일반적인 "프로그래밍 가능 완료"보다 약간 낮은 수준에서 작동합니다 (명령이 식별 될 때만 호출되며 위에서 식별 한 두 가지 특수한 경우).
업데이트 : bash-5.0 (2019 년 1 월)의 새로운 릴리스는 complete -I
이 문제를 정확하게 추가합니다 .
관련 readline 명령은 다음과 같습니다.
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.
보다 일반적인 방법과 비슷하게이 complete -F
중 일부를 사용하여 함수로 넘길 수 있습니다 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'
이를 통해 고유 한 명령 또는 접두사 문자열 후크를 사용할 수 ~/.complete.d/
있습니다. 예를 들어 다음을 사용하여 실행 파일을 만드는 경우 ~/.complete.d/loc
:
#!/bin/bash
echo localc
이것은 당신이 기대하는 것을 (거의) 할 것입니다.
위의 함수는 불완전하지만 (특히 sort | fmt | column
일치 목록을 표시하는 모호한 캐리 온) 정상적인 bash 명령 완료 동작을 에뮬레이트하기 위해 약간의 길이로 진행됩니다 .
그러나 이것 에 대한 사소한 문제는 함수를 사용하여 기본 complete
기능 (기본적으로 TAB으로 호출)에 대한 바인딩을 대체 할 수 있습니다 .
이 접근 방식은 사용자 지정 명령 완성에만 사용되는 다른 키 바인딩과 잘 작동하지만 그 이후에는 전체 완성 논리를 구현하지 않습니다 (예 : 명령 줄의 이후 단어). 그렇게하려면 명령 줄을 구문 분석하고 커서 위치를 다루고 쉘 스크립트에서 고려해야 할 까다로운 까다로운 것들이 필요합니다 ...
loc
을 고려 했습니까localc
? 꽤 오랜 시간 파고 검색 한 후에 bash 완성을이 방법으로 사용자 정의하는 방법을 찾지 못했기 때문에 대안을 제안합니다. 가능하지 않을 수 있습니다.