The following code, adapted from this Stack Overflow answer and this Ubuntu Forums discussion thread will add completions for all your defined aliases:
# 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
For simple (command only, no arguments) aliases it will assign the original completion function to the alias; for aliases with arguments, it creates a wrapper function that inserts the extra arguments into the original completion function.
Unlike the scripts it has evolved from, the function respects quotes both for the alias command and its arguments (but the former have to be matched by the completion command, and cannot be nested), and it should reliably filter out aliases to command lists and pipes (which are skipped, as it is impossible to find out what to complete in them without re-creating the complete shell command line parsing logic).
Usage
Either save the code as a shell script file and source that in, or copy the function wholesale into, .bashrc
(or your pertinent dot file). The important thing is to call the function after both bash completion and alias definitions have been set up (the code above calls the function right after its definition, in a “source and forget” spirit, but you can move the call anywhere downstream if that suits you better). If you don’t want the function in your environment after it exits, you can add unset -f alias_completion
after calling it.
Notes
If you are using bash
4.1 or above and use dynamically-loaded completions, the script will attempt to load completions for all of your aliased commands so that it can build the wrapper functions for your aliases.
1@MichaelDurrant Are you sure that this is actually built in for aliases? I am on Ubuntu 15.10 with Bash 4.3.42(1)-release (x86_64-pc-linux-gnu) and there is no such thing. I also tested a few earlier releases. So for example if you type in
ll --[TAB]
it will print a list of options forls
? I'm pretty skeptical of this, but if you're sure such a thing existed in 11.10 I'd be curious to dig through it and determine what was removed. – Six – 2015-11-23T14:49:28.250What OS and bash are you using? I am on Ubuntu 11.10 and bash 4.2.10(1)-release (x86_64-pc-linux-gnu) and I have this functionaity built in to my shell for my many aliases. btw
bash --version
to get this (don't use-v
, different output). – Michael Durrant – 2012-06-16T13:14:51.163Sorry missed taht bit of info - OSX Lion, GNU bash, version 3.2.48(1)-release (x86_64-apple-darwin11) – dstarh – 2012-06-18T13:10:30.937
1@killermist: unless I’m completely mistaken, zsh doesn’t complete aliased commands out of the box either. Implementing a function that adds defined aliases to completion appears to be much easier than for bash, though, as zhs’s completion system seems both more powerful and more straightforward than bash’s. – kopischke – 2012-06-23T19:22:10.967
Cross site duplicate: http://stackoverflow.com/questions/342969/how-do-i-get-bash-completion-to-work-with-aliases/1793178
– Ciro Santilli 新疆改造中心法轮功六四事件 – 2014-01-20T08:57:36.447@ciro I agree that the question is a bit dupe but IMO this answer addresses the Subject of the question, not JUST the example in the question. – dstarh – 2014-01-20T14:03:37.033
@dstarh do you mean that that question is focused on specific example (
git checkout
) while yours is about general tab completion for all aliases? If this is it I disagree since the other question says "Ideally I'd like autocompletion to just magically work for all my aliases", so it seems he wants a general solution for any program. Also nogit
tag either there. – Ciro Santilli 新疆改造中心法轮功六四事件 – 2014-01-20T14:40:01.027@ciro No, the title of the SO question is "How do I get bash completion to work with aliases?", the title for this question is "How can I get bash to perform tab-completion for my aliases?". The selected answer for the SO question answers the example whereas the selected answer here answers the title, so I feel this is a better answer regardless of it being a duplicate or not. – dstarh – 2014-01-20T15:30:53.567