Hoàn thành lệnh (cùng với những thứ khác) được xử lý thông qua hoàn thành bash readline . Điều này hoạt động ở mức thấp hơn một chút so với "hoàn thành lập trình" thông thường (chỉ được gọi khi lệnh được xác định và hai trường hợp đặc biệt bạn đã xác định ở trên).
Cập nhật: bản phát hành mới của bash-5.0 (tháng 1 năm 2019) bổ sung complete -I
chính xác cho vấn đề này.
Các lệnh đọc có liên quan là:
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.
Theo cách tương tự như phổ biến hơn complete -F
, một số trong số này có thể được chuyển giao cho một chức năng bằng cách sử dụng 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'
Điều này cho phép móc chuỗi tiền tố hoặc tiền tố của riêng bạn vào ~/.complete.d/
. Ví dụ: nếu bạn tạo một tệp thực thi ~/.complete.d/loc
với:
#!/bin/bash
echo localc
Điều này sẽ làm (khoảng) những gì bạn mong đợi.
Hàm trên có một số độ dài để mô phỏng hành vi hoàn thành lệnh bash bình thường, mặc dù nó không hoàn hảo (đặc biệt là phần sort | fmt | column
mang theo đáng ngờ để hiển thị danh sách các trận đấu).
Tuy nhiên , một vấn đề không hề nhỏ với vấn đề này, nó chỉ có thể sử dụng một hàm để thay thế liên kết thành complete
hàm chính (được gọi bằng TAB theo mặc định).
Cách tiếp cận này sẽ hoạt động tốt với một ràng buộc khóa khác được sử dụng để hoàn thành lệnh tùy chỉnh, nhưng đơn giản là nó không thực hiện logic hoàn thành đầy đủ sau đó (ví dụ: các từ sau trong dòng lệnh). Làm như vậy sẽ yêu cầu phân tích dòng lệnh, xử lý vị trí con trỏ và những thứ khó khăn khác có lẽ không nên được xem xét trong tập lệnh shell ...
loc
đểlocalc
? Tôi đề nghị các lựa chọn thay thế bởi vì sau một thời gian đào bới và tìm kiếm, tôi không tìm thấy cách nào để tùy chỉnh hoàn thành bash theo cách này. Nó có thể là không thể.