Le code suivant, adapté de cette réponse au débordement de pile et à ce fil de discussion des forums Ubuntu ajoutera des compléments à tous vos alias définis:
# 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
Pour les alias simples (commande seulement, sans arguments), il affectera la fonction d'achèvement d'origine à l'alias; pour les alias avec arguments, il crée une fonction wrapper qui insère les arguments supplémentaires dans la fonction d'achèvement d'origine.
Contrairement aux scripts qu'il a évolué à partir, la fonction respecte guillemets les deux pour la commande alias et ses arguments (mais les premiers doivent correspondre par la commande d'achèvement, et ne peut pas être imbriquées), et il devrait filtrer de manière fiable les alias des listes de commandes et les tubes (qui sont ignorés, car il est impossible de savoir quoi compléter sans recréer la logique d'analyse complète de la ligne de commande du shell).
Usage
Enregistrez le code en tant que fichier de script shell et indiquez -le dans la source , ou copiez la fonction en gros dans .bashrc
(ou dans votre fichier de points pertinent ). L’important est d’appeler la fonction après que les définitions d’achèvement de bash et d’alias ont été définies (le code ci-dessus appelle la fonction juste après sa définition, dans un esprit «source et oublie», mais vous pouvez déplacer l’appel n'importe où en aval si te va mieux). Si vous ne voulez pas que la fonction soit dans votre environnement après sa fermeture, vous pouvez l'ajouter unset -f alias_completion
après l'avoir appelée.
Remarques
Si vous utilisez la version bash
4.1 ou une version ultérieure et que vous utilisez des achèvements chargés de manière dynamique, le script tente de charger les achèvement de toutes vos commandes avec alias afin de pouvoir créer les fonctions d'encapsulation pour vos alias.
bash --version
pour obtenir cela (ne pas utiliser-v
, sortie différente).