El siguiente código, adaptado de esta respuesta de desbordamiento de pila y este hilo de discusión de los foros de Ubuntu agregará terminaciones para todos sus alias definidos:
# 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
Para los alias simples (solo comando, sin argumentos) asignará la función de finalización original al alias; para los alias con argumentos, crea una función de contenedor que inserta los argumentos adicionales en la función de finalización original.
A diferencia de los scripts a partir de los cuales ha evolucionado, la función respeta las comillas tanto para el comando de alias como para sus argumentos (pero el primero debe coincidir con el comando de finalización y no puede anidarse), y debe filtrar de manera confiable los alias a las listas de comandos y tuberías (que se omiten, ya que es imposible saber qué completar en ellas sin volver a crear la lógica de análisis de la línea de comandos de shell completa).
Uso
Guarde el código como un archivo de script de shell y fuente que, o copie la función al por mayor, .bashrc
(o su archivo de puntos pertinente ). Lo importante es llamar a la función después de que se hayan configurado las definiciones de alias y de finalización de bash (el código anterior llama a la función justo después de su definición, en un espíritu de "fuente y olvido", pero puede mover la llamada a cualquier lugar aguas abajo si eso te queda mejor). Si no desea la función en su entorno después de que se cierre, puede agregarla unset -f alias_completion
después de llamarla.
Notas
Si está utilizando bash
4.1 o superior y usa terminaciones cargadas dinámicamente, el script intentará cargar las terminaciones para todos sus comandos con alias para que pueda construir las funciones de contenedor para sus alias.
bash --version
para obtener esto (no use-v
, salida diferente).