How do I get bash completion for command aliases?
I am looking to get tab-completion on my command line aliases, for example, say I defined the following alias :
alias apt-inst='sudo aptitude install'
Is there a way to get the completions provided by aptitude when I hit the tab key? i.e. when I write ‘sudo aptitude install gnumer’ and hit tab, aptitude completes this to gnumeric, or if there was uncertainty lists all the available packages starting with gnumer. If I do it using my alias, nothing – no completion.
There is a great thread about this on the Ubuntu forums. Ole J proposes the following alias completion definition function:
function make-completion-wrapper () {
local function_name="$2"
local arg_count=$(($#-3))
local comp_function_name="$1"
shift 2
local function="
function $function_name {
((COMP_CWORD+=$arg_count))
COMP_WORDS=( "$@" ${COMP_WORDS[@]:1} )
"$comp_function_name"
return 0
}"
eval "$function"
echo $function_name
echo "$function"
}
Use it to define a completion function for your alias, then specify that function as a completer for the alias:
make-completion-wrapper _apt_get _apt_get_install apt-get install
complete -F _apt_get_install apt-inst
I prefer to use aliases for adding always-used arguments to existing programs. For instance, with grep
, I always want to skip devices and binary files, so I make an alias for grep
. For adding new commands such as grepbin
, I use a shell script in my ~/bin
folder. If that folder is in your path, it will get autocompleted.
Here’s the code from Shawn J. Goff’s answer with some improvements:
- Fixed syntax errors highlighted by
shell-check
, eg the first"
of"$@"
actually ended the function definition string. - Removed the
return 0
so that the return value of the underlying function can be passed back to the caller.
.
# Wraps a completion function, eg for use with an alias.
# Usage:
# make-completion-wrapper <actual completion function> <name of new func.>
# <command name> <list supplied arguments>
# eg.
# alias agi='apt-get install'
# make-completion-wrapper _apt_get _apt_get_install apt-get install
# # defines a function called _apt_get_install (that's $2) that will
# # complete the 'agi' alias.
# complete -F _apt_get_install agi
function make-completion-wrapper {
local function_name="$2"
local arg_count=$(( $#-3 ))
local comp_function_name="$1"
shift 2
local function="function $function_name {
(( COMP_CWORD += $arg_count ))
COMP_WORDS=( "$@" ${COMP_WORDS[@]:1} )
"$comp_function_name"
}"
eval "$function"
# echo "$function"
}
export -f make-completion-wrapper
Try complete-alias, which solves this problem exactly. (Disclaimer: I am the author of complete_alias
)
After install it you can use one generic function to complete many aliases like this:
complete -F _complete_alias <myalias1>
complete -F _complete_alias <myalias2>
complete -F _complete_alias <myalias3>
You may want to source the complete_alias
file in every bash instance through .bash_profile
or similar.
installation
mkdir ~/.bash_completion.d
curl https://raw.githubusercontent.com/cykerway/complete-alias/master/complete_alias
> ~/.bash_completion.d/complete_alias
application
source ~/.bash_completion.d/complete_alias
alias container=docker container
complete -F _complete_alias container
container
can now be autocompleted by the original _docker()
completion handler;
$ container l<Tab>
logs ls
$ container s<Tab>
start stats stop
2018 answer
You must add your alias to the program ‘complete’. Depending the kind of autocompletion you want to achieve, you must use -c or -F.
For package autocompletion:
complete -c name_of_your_alias
For command autocompletion:
complete -F name_of_your_alias
To check if your alias was added correctly:
complete | grep name_of_your_alias
Finally, to remove an alias from ‘complete’:
complete -r name_of_your_alias
In your case:
complete -c apt-inst
As an extension to @Giles answer, the following convenience function auto-names the wrapper generated by make-completion-wrapper
to make it possible to define completion in one line:
function complete-alias {
# uses make-completion-wrapper: https://unix.stackexchange.com/a/4220/50978
# example usage
# complete-alias _pass pshow pass show
# complete-alias _pass pgen pass generate
EXISTING_COMPLETION_FN=${1} && shift
ALIAS=${1} && shift
AUTOGEN_COMPLETION_FN="__autogen_completion_${ALIAS}"
make-completion-wrapper ${EXISTING_COMPLETION_FN} ${AUTOGEN_COMPLETION_FN} ${*}
complete -F ${AUTOGEN_COMPLETION_FN} ${ALIAS}
}
By googling this issue I ended up here, so I tried the approaches in the other answers. For various reasons I don’t actually understand, they never behaved properly in my Ubuntu 16.04.
What in the end worked for me was way more trivial than expected. I wanted to use the same autocompletion as rsync
has for mycommand
. Hence, I looked up the autocompletion function, and then called complete
accordingly.
# Lookup of name of autocompletion function used for rsync
complete -p rsync
# Returns: complete -o nospace -F _rsync rsync
# Sourcing the rsync functions before, then using the same function for 'mycommand'
. /usr/share/bash-completion/completions/rsync
complete -o nospace -F _rsync mycommand
Disclaimer: I’m not sure what’s the downside of my approach compared to the others. I mainly wrote this as it could help people where this trivial approach might be enough.
Own local completions may be defined in ~/.local/share/bash-completion/completions
as explained in the bash-completion FAQs
A simple approach is thus to create this directory (if not existing) and put a file named mycommand
(with alias mycommand='realcommand'
as the alias definition) and to just a) source the original command’s completion and b) refer to the function in complete
, e.g.:
$cat ~/.local/share/bash-completion/completions/mycommand
source /usr/share/bash-completion/completions/realcommand
complete -F _realcommand mycommand
If the function is called _realcommand
. Use completion on realcommand
and then complete -p | grep realcommand
to see how the function is actually called.
If the alias is meant to be system-wide, one may as well place the file in /usr/share/bash-completion/completions/
directly.
Limitations
-
Needs manually adding the entry for each alias, not automated.
-
Fails if the completion function refers to the command itself:
It worked nicely for e.g. alias userctl='systemctl --user'
, it (partly) failed for alias mylsblk=lsblk
when tab-completing anything other than mylsblk -<TAB>
. This is due to the function _lsblk_module
referring to the command name (via $1
) in the completion script and this fails as mylsblk
cannot be found as command. It worked, when I replaced $1
with lsblk
in the completion script of lsblk
(not recommended, done for testing purposes only).
In this case, the local completion script has to be slightly adapted so that the first argument remains the command name:
source /usr/share/bash-completion/completions/lsblk
_lsblk_dummy() { _lsblk_module lsblk ; }
complete -F _lsblk_dummy mylsblk
which might as well be seen as general approach.
I came up with the following solution; in my case I aliased k
to kubectl
, and wanted to have bash completion for the k
alias as well:
-
Make sure the
bash-completion
package is installed (that’s the correct package name on Debian/Ubuntu/RHEL; it might be different on other distributions). -
Create a file
/usr/share/bash-completion/completions/k
with the following content:# Load completion for the kubectl command: . /usr/share/bash-completion/completions/kubectl # Get the completion definition for kubectl (in the form of "complete ... kubectl"): __k_kubectl_comp=$(complete -p kubectl) # Transform "complete ... kubectl" into "complete ... k" by replacing the last # word, and eval the result: eval "${__k_kubectl_comp% *} k" # That's it, clean up! unset __k_kubectl_comp
-
Now the
k
alias should have the same completion as thekubectl
command (you might have to open a new shell first).
This will essentially retrieve the complete
command for kubectl
, modify it so that it applies to the k
alias, and run the resulting command. For example, complete -p kubectl
on my system prints:
complete -o default -F __start_kubectl kubectl
The shell script above will transform this to complete -o default -F __start_kubectl k
, and run that command.
Footnote: The directory to drop bash completion code snippets into is not necessarily always /usr/share/bash-completion/completions
. You can get the directory that your system uses by running pkg-config --variable=completionsdir bash-completion
(see also the README of the bash-completion
package).
I have noticed that a few responses are concerned with autocompleting with kubectl
aliases. While other answers have addressed how to have auto complete on an alias for kubectl
, they will not work when you have an alias for something like kubectl describe pod
. I believe this is related to how kubectl
does completion and not about completion in general.
Alias completion for kubectl version 1.27.1
Putting the following in my .bash_profile
works to get multiword kubectl
aliases working for v1.27.1:
# Load kubectl completion functions
# Need to run:
# kubectl completion bash > ~/.kubectl-completion
# To generate the .kubectl-completion file
source ~/.kubectl-completion
# Create the pod-show alias
alias pod-show="kubectl describe pod"
# Modified from the accepted answer
__start_kubectl_pods() {
local compl
compl=${COMP_WORDS[@]:1}
(( COMP_CWORD += 2 ))
COMP_WORDS=( kubectl describe pod "${compl:- }" )
__start_kubectl
}
# Setup completion
complete -o default -F __start_kubectl_pods pod-show
A couple of notes:
- the
__start_kubectl
is the main function for completingkubectl
commmands. This function requires a space at the end to do completion on no arguments. I believe this is why the accepted answer does not work out of the box. - Running
export BASH_COMP_DEBUG_FILE=compdebug
and then trying the completion outputs debug logs to a file named compdebug. This helped with figuring this out.