Наступний код, адаптований з цієї відповіді на переповнення стека та цього дискусійного потоку Ubuntu Forums , додасть завершення для всіх ваших визначених псевдонімів:
# Automatically add completion for all aliases to commands having completion functions
function alias_completion {
local namespace="alias_completion"
# parse function based completion definitions, where capture group 2 => function and 3 => trigger
local compl_regex='complete( +[^ ]+)* -F ([^ ]+) ("[^"]+"|[^ ]+)'
# parse alias definitions, where capture group 1 => trigger, 2 => command, 3 => command arguments
local alias_regex="alias ([^=]+)='(\"[^\"]+\"|[^ ]+)(( +[^ ]+)*)'"
# create array of function completion triggers, keeping multi-word triggers together
eval "local completions=($(complete -p | sed -Ene "/$compl_regex/s//'\3'/p"))"
(( ${#completions[@]} == 0 )) && return 0
# create temporary file for wrapper functions and completions
rm -f "/tmp/${namespace}-*.tmp" # preliminary cleanup
local tmp_file; tmp_file="$(mktemp "/tmp/${namespace}-${RANDOM}XXX.tmp")" || return 1
local completion_loader; completion_loader="$(complete -p -D 2>/dev/null | sed -Ene 's/.* -F ([^ ]*).*/\1/p')"
# read in "<alias> '<aliased command>' '<command args>'" lines from defined aliases
local line; while read line; do
eval "local alias_tokens; alias_tokens=($line)" 2>/dev/null || continue # some alias arg patterns cause an eval parse error
local alias_name="${alias_tokens[0]}" alias_cmd="${alias_tokens[1]}" alias_args="${alias_tokens[2]# }"
# skip aliases to pipes, boolean control structures and other command lists
# (leveraging that eval errs out if $alias_args contains unquoted shell metacharacters)
eval "local alias_arg_words; alias_arg_words=($alias_args)" 2>/dev/null || continue
# avoid expanding wildcards
read -a alias_arg_words <<< "$alias_args"
# skip alias if there is no completion function triggered by the aliased command
if [[ ! " ${completions[*]} " =~ " $alias_cmd " ]]; then
if [[ -n "$completion_loader" ]]; then
# force loading of completions for the aliased command
eval "$completion_loader $alias_cmd"
# 124 means completion loader was successful
[[ $? -eq 124 ]] || continue
completions+=($alias_cmd)
else
continue
fi
fi
local new_completion="$(complete -p "$alias_cmd")"
# create a wrapper inserting the alias arguments if any
if [[ -n $alias_args ]]; then
local compl_func="${new_completion/#* -F /}"; compl_func="${compl_func%% *}"
# avoid recursive call loops by ignoring our own functions
if [[ "${compl_func#_$namespace::}" == $compl_func ]]; then
local compl_wrapper="_${namespace}::${alias_name}"
echo "function $compl_wrapper {
(( COMP_CWORD += ${#alias_arg_words[@]} ))
COMP_WORDS=($alias_cmd $alias_args \${COMP_WORDS[@]:1})
(( COMP_POINT -= \${#COMP_LINE} ))
COMP_LINE=\${COMP_LINE/$alias_name/$alias_cmd $alias_args}
(( COMP_POINT += \${#COMP_LINE} ))
$compl_func
}" >> "$tmp_file"
new_completion="${new_completion/ -F $compl_func / -F $compl_wrapper }"
fi
fi
# replace completion trigger by alias
new_completion="${new_completion% *} $alias_name"
echo "$new_completion" >> "$tmp_file"
done < <(alias -p | sed -Ene "s/$alias_regex/\1 '\2' '\3'/p")
source "$tmp_file" && rm -f "$tmp_file"
}; alias_completion
Для простих псевдонімів (лише для команд, без аргументів) він присвоює псевдоніму функцію початкового завершення; для псевдонімів з аргументами він створює функцію обгортки, яка вставляє зайві аргументи в оригінальну функцію завершення.
На відміну від скриптів, з яких вона розвинулася, функція поважає цитати як для команди псевдоніму, так і для його аргументів (але перші повинні відповідати команді завершення і не можуть бути вкладені), і вона повинна надійно фільтрувати псевдоніми до списків команд і труби (які пропускаються, оскільки неможливо з'ясувати, що в них виконати, не відтворюючи логіку розбору командного рядка повного оболонки).
Використання
Або збережіть код як файл сценарію оболонки та джерело, яке знаходиться у ньому, або скопіюйте функцію оптом у .bashrc
(або ваш відповідний крапковий файл ). Найважливіше - викликати функцію після того, як було встановлено як завершення bash, так і визначення псевдонімів (код вище викликає функцію відразу після її визначення, в дусі "джерело і забудь", але ви можете переміщати виклик куди завгодно нижче, якщо це вам більше підходить). Якщо ви не хочете, щоб функція була у вашому оточенні після її завершення, ви можете додати її unset -f alias_completion
після виклику.
Примітки
Якщо ви використовуєте bash
4.1 або вище та використовуєте динамічно завантажені доповнення, скрипт буде намагатися завантажити завершення для всіх ваших відчужених команд, щоб він міг будувати функції обгортки для ваших псевдонімів.
bash --version
щоб отримати це (не використовувати-v
, різний вихід).