Ask Ubuntu is a question and answer site for Ubuntu users and developers. It's 100% free.

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

When I open up the command line and type in git, I get a bunch of completions for arguments of git, like add, commit, merge, and so on.

How do I add this kind of completion to my own apps?

So far, I've been able to specify the first level of completion like this:

$ complete -W "asd asdf" ./

$ ./ asd
asd asdf

But it tries to keep going after that:

$ ./ asdf asd
asd asdf

I've tried setting a completion for the second level by running complete -W "lol" "./ asd", but that doesn't work.

What's the proper way to set these up? And once I've figured out all of the commands, where do I have to put them? Running a big list of these commands in .bashrc, every time a terminal is opened, doesn't seem too efficient (plus I don't want to mess with users' files if I don't have to).

share|improve this question
up vote 22 down vote accepted

All of the bash completions are stored in /etc/bash_completion.d/. So if you're building software with bash_completion it would be worthwhile to have the deb/make install drop a file with the name of the software in that directory. Here's an example bash completion script for Rsync:

# bash completion for rsync

have rsync &&
    # TODO: _split_longopt

    local cur prev shell i userhost path   


    _expand || return 0

    case "$prev" in
        return 0
        _filedir -d
        return 0
        COMPREPLY=( $( compgen -W 'rsh ssh' -- "$cur" ) )
        return 0

    case "$cur" in
        COMPREPLY=( $( compgen -W '-v -q  -c -a -r -R -b -u -l -L -H \
            -p -o -g -D -t -S -n -W -x -B -e -C -I -T -P \
            -z -h -4 -6 --verbose --quiet --checksum \
            --archive --recursive --relative --backup \
            --backup-dir --suffix= --update --links \
            --copy-links --copy-unsafe-links --safe-links \
            --hard-links --perms --owner --group --devices\
            --times --sparse --dry-run --whole-file \
            --no-whole-file --one-file-system \
            --block-size= --rsh= --rsync-path= \
            --cvs-exclude --existing --ignore-existing \
            --delete --delete-excluded --delete-after \
            --ignore-errors --max-delete= --partial \
            --force --numeric-ids --timeout= \
            --ignore-times --size-only --modify-window= \
            --temp-dir= --compare-dest= --compress \
            --exclude= --exclude-from= --include= \
            --include-from= --version --daemon --no-detach\
            --address= --config= --port= --blocking-io \
            --no-blocking-io --stats --progress \
            --log-format= --password-file= --bwlimit= \
            --write-batch= --read-batch= --help' -- "$cur" ))
        # find which remote shell is used
        for (( i=1; i < COMP_CWORD; i++ )); do
            if [[ "${COMP_WORDS[i]}" == -@(e|-rsh) ]]; then
        if [[ "$shell" == ssh ]]; then
            # remove backslash escape from :
            # unescape spaces
            path=${path//\\\\\\\\ / }
            if [ -z "$path" ]; then
                # default to home dir of specified
                # user on remote host
                path=$(ssh -o 'Batchmode yes' $userhost pwd 2>/dev/null)
            # escape spaces; remove executables, aliases, pipes
            # and sockets; add space at end of file names
            COMPREPLY=( $( ssh -o 'Batchmode yes' $userhost \
                command ls -aF1d "$path*" 2>/dev/null | \
                sed -e 's/ /\\\\\\\ /g' -e 's/[*@|=]$//g' \
                -e 's/[^\/]$/& /g' ) )
        _known_hosts_real -c -a "$cur"

    return 0
} &&
complete -F _rsync $nospace $filenames rsync

# Local variables:
# mode: shell-script
# sh-basic-offset: 4
# sh-indent-comment: t
# indent-tabs-mode: nil
# End:
# ex: ts=4 sw=4 et filetype=sh

It would likely be worthwhile to review one of the bash completion files in there that most closely matches your program. One of the simplest examples is the rrdtool file.

share|improve this answer
I've been wondering this for quite some time. Great answer. Plus one! – weberc2 Sep 26 '13 at 21:24
Can we configure completions to load from other locations? IE. ~/.local – Chris Jul 31 '14 at 16:14
Yes, you can put a file like this wherever you want and then put source ~/.local/mycrazycompletion in your ~/.bashrc – Stefano Palazzo Mar 22 at 5:40

Your Answer


By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.