136

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.

1

10 Answers 10

106

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   
10
  • 5
    Given that this software seems to be yours, you could do better than this. Add instructions on installing it. Describe what it does and how to use it. Otherwise this is just spam.
    – muru
    Commented Dec 24, 2016 at 7:55
  • 6
    @muru I was thinking of pasting some code here but it's probably longer than accepted here. I'd assume people have no problem reading the Install section in a README file, and in this case it's only several lines.
    – Cyker
    Commented Dec 25, 2016 at 12:12
  • 3
    the point is to be able to judge whether visiting said README is worthwhile, just from the answer.
    – muru
    Commented Dec 25, 2016 at 12:14
  • 4
    This is an adequate answer and it solves the problem exactly. Commented Oct 10, 2018 at 23:16
  • 9
    This is an excellent and very comprehensive answer that works perfectly, thanks!. It's probably been updated since @muru had problems with it. Commented Oct 19, 2018 at 20:21
51

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))
      # Quotes here are important
      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.

7
  • 2
    Awesome, I was afraid it wouldn't be possible.
    – levesque
    Commented Nov 20, 2010 at 17:10
  • Note this code has some issues. See my answer for their explanation and resolution.
    – Tom Hale
    Commented Sep 15, 2016 at 13:06
  • Note: I was using this technique for another command, and I had to use complete -o default -F ... instead of complete -F ... to get things like filename auto-completion working correctly when passing args (Bash 4.3.46). Commented Dec 19, 2016 at 14:39
  • I am struggling to get this working for kubectl. Here is what I am trying: alias ks=kubectl\ --context=staging; make-completion-wrapper __start_kubectl _ks kubectl --context=staging; ` complete -F _ks ks; when I type ks g` it correctly completes to ks get but then when i type ks get p I don't get expected completions like 'pods`. Am I doing something wrong?
    – kortina
    Commented May 8, 2020 at 23:07
  • [update]: I think the underlying problem for me is w kubectl, not the alias... kubectl get p also does not complete as expected.
    – kortina
    Commented May 8, 2020 at 23:24
20

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
_completion_loader 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.

5
  • 2
    It seems that bash says bash: complete: XYZ: no completion specification until you actually try to complete with XYZ the first time. I think editing the user .bash_completion file is the way to go, though I'm still not sure how...
    – Myridium
    Commented May 17, 2020 at 22:50
  • 4
    Turns out that the way to do this is call _completion_loader rsync first, to make sure the completion function is loaded. It is sometimes (always?) loaded only when you try to autocomplete with the function for the first time. This answer also has another problem: it cannot autocomplete with the context of arguments provided. E.g. it cannot make an alias for pass -c autocomplete like pass -c, only like pass. These are different.
    – Myridium
    Commented Jun 30, 2020 at 8:10
  • what about a command with sub-command like git checkout?
    – aless80
    Commented Jan 19, 2023 at 10:10
  • this worked and it was quite simple. to avoid having to duplicate the complete options, you can print the completion dynamically like so: $(complete -p rsync | rev | cut -d' ' -f 2- | rev) mycommand
    – jyn
    Commented Feb 3 at 18:29
  • also, . /usr/share/bash-completions doesn't work if the command is installed locally (e.g. ~/.local/bin or /usr/local/share). instead try __load_completion rsync (stackoverflow.com/a/61544119)
    – jyn
    Commented Feb 3 at 18:47
3

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
2
  • Doesn't work for me in Bash 4.3.46 I'm afraid. Shaun J. Goff's answer does work. Commented Dec 19, 2016 at 14:38
  • 1
    "Ending" the function definition string is on purpose; the point is to include arguments from the outer function into the COMP_WORDS array. If we use make-completion-wrapper _apt_get _apt_get_install apt-get install as an example, after shift 2, $@ contains apt-get install. The function definition includes apt-get install (the two literal words) when assigning COMP_WORDS.
    – Jeffery To
    Commented Jun 3, 2019 at 19:58
3

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
5
  • 2
    Please don’t continue your answer in comments. If you have things to say, edit them into the answer. Commented May 21, 2018 at 3:02
  • 7
    complete -F xxx does not work on OSX (It just shows the usage complete: usage: complete [-abcdefgjksuv] [-pr] [-o option] [-A action] [-G globpat] [-W wordlist] [-P prefix] [-S suffix] [-X filterpat] [-F function] [-C command] [name ...]) . Do you have any pointer? Thanks. Commented Feb 28, 2019 at 22:20
  • 3
    Use this instead: unix.stackexchange.com/questions/224227/…
    – Rich
    Commented Jun 5, 2019 at 8:20
  • 1
    This is great information except for not resolving the situation asked in the question. :)
    – dannysauer
    Commented Oct 6, 2020 at 18:38
  • Sorry, but executing complete -F name_of_your_alias simply makes no sense. Moreover, it simply fails, because it requires an additional argument.
    – dsimic
    Commented Jun 9 at 20:15
3

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}
}
2

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

  1. Needs manually adding the entry for each alias, not automated.

  2. 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.

2
  • Awesome thanks! Works for me with an alias from docker to just the character d. The alias gets completion even on docker CLI sub-commands like d create . Just press "TAB"! My installation notes here: github.com/dgroomes/my-config/commit/…
    – dgtc
    Commented Feb 19, 2022 at 19:34
  • I used /etc/bash_completion.d/ in Debian bullseye with kubectl. I added the kubectl comletions there and also the alias file k sourcing kubectl. Both in the same dir. complete -p | grep kubectl was really useful.
    – The Fool
    Commented Mar 15, 2022 at 19:00
0

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:

  1. 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).

  2. 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
    
  3. Now the k alias should have the same completion as the kubectl 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).

3
0

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 completing kubectl 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.
0

The accepted answer is close but fails with some completion functions (e.g. completing an alias for npm run) due to quoting issues within its call to eval.

Here's a solution that builds on Shawn Goff's and user84207's answers, with the following improvements:

  • Fixes quoting issues
  • Fixes shellcheck warnings
  • Puts the minimal amount of logic inside eval so the code is easier to reason about (and can be checked with shellcheck).
# Adapted from https://unix.stackexchange.com/a/531400/10183
# Example usage: complete-alias _pass pgen pass generate
complete_alias() {
  local old_completion_fn="$1" && shift
  local alias_name="$1" && shift
  local new_completion_fn="_alias_completion__${alias_name}"
  bind_function "$new_completion_fn" alias_completion_wrapper "$old_completion_fn" "$alias_name" "$@"
  complete -o default -F "$new_completion_fn" "$alias_name"
}

# Adapted from:
# - https://unix.stackexchange.com/a/4220/50978
# - https://superuser.com/a/437508/56109
alias_completion_wrapper() {
  local old_completion_fn="$1" && shift
  local alias_name="$1" && shift
  local alias_command=("$@")
  local arg_count=$(($# - 1))

  ((COMP_CWORD+=$arg_count))
  COMP_WORDS=( "${alias_command[@]}" "${COMP_WORDS[@]:1}" )
  (( COMP_POINT -= ${#COMP_LINE} ))
  COMP_LINE=${COMP_LINE/#$alias_name/${alias_command[@]}}
  (( COMP_POINT += ${#COMP_LINE} ))
  $old_completion_fn
}

# Creates a new function with the given name (arg 1) that calls the given
# source function (arg 2) with the given arguments (remaining args).
bind_function() {
  local dest_fn src_fn bind_args
  printf -v dest_fn "%q" "$1" && shift
  printf -v src_fn "%q" "$1" && shift
  printf -v bind_args "%q " "$@"
  eval "function $dest_fn() { $src_fn $bind_args; }"
}

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .