3

Bash lets you complete commands names and names of files in the arguments with the TAB key. But why not also common options to commands? Why not, even better, a completion system that tells you what an option does, too?

I heard of programmable completion.. but don't understand where it fits..

So my question is: is there a way to achieve what I ask? Other tools to combine with Bash maybe.. or anything?

luca
  • 12,311
  • 15
  • 70
  • 103

7 Answers7

5

If you want even more awesome completion, look into zsh. It's very much like bash, and takes some of the good features from ksh, tcsh, etc. It also fixes a few of the annoying bash bugs.

It can do some pretty cool stuff, including completing remote filenames for scp (if you have key-based authentication set up) and mini-documentation when you tab complete For example, I was pleasantly surprised when I tabbed on "jar" the other day:

[steven@sexy:~]% jar <tab>
0  -- store only without using ZIP compression
M  -- do not create manifest file
etc...
Steven Schlansker
  • 37,580
  • 14
  • 81
  • 100
2

Here's the official man page of bash: Bash Reference Manual: Programmable Completion

tangens
  • 39,095
  • 19
  • 120
  • 139
2

On OS X, you can easily install a set of predefined bash completions using MacPorts by following the instructions here. Looking at the examples in /opt/local/etc/bash_completion.d may give you some ideas for making additional ones.

Ned Deily
  • 83,389
  • 16
  • 128
  • 151
1

It's a standard feature of bash: programmable completion.

Ned Batchelder
  • 364,293
  • 75
  • 561
  • 662
1

Bash does support argument completion: http://www.debian-administration.org/articles/316

vrutberg
  • 1,981
  • 1
  • 20
  • 28
1

Bash completion is very customisable and can display options to common commands. The configuration file just need to specify so. In Debian, bash completion comes with an assorted set of configuration files that complete options for different commands.

For example:

alanhaggai@neon:~$ tar
A  c  d  r  t  u  x
Alan Haggai Alavi
  • 72,802
  • 19
  • 102
  • 127
0

I don't like any of the answers here and would like to contribute a couple concrete examples.

I sometimes have a number of directories with a common prefix and wanted to be able to cd into them with completion by just typing the unique part of the directory name which would be in the middle or end of the directory name.

I was able to write a completion function to accomplish this:

_cd(){
    # Backup old nullglob setting
    local shoptbakup="`shopt -p nullglob`"
    shopt -s nullglob

    local cur opts i opt
    local IFS=$'\n'
    cur="${COMP_WORDS[COMP_CWORD]}"

    # Home directory substitution
    if [[ "${cur:0:1}" == '~' ]]; then
        cur="$HOME/${cur:1}"
    fi

    if [[ $cur == */* ]]; then
        opts=(${cur}*/)
    else
        opts=(*${cur}*/)
    fi

    # Prevent trailing//
    i=0
    for opt in "${opts[@]}"; do
        #opts[$i]=${opt%${opt##*[!/]}}
        opts[$i]=${opt%/}
        i=$((i+1))
    done

    # Restore nullglob setting
    eval "$shoptbakup" 2>/dev/null

    COMPREPLY=("${opts[@]}")
}
complete -o filenames -o bashdefault -o nospace -F _cd cd

So now from my prompt I can do this:

$ ls
test 6/  test 7/  test 8/  test1/  test2/  test3/  test4/  test5/
$ cd 7[TAB]

And it automatically completes to:

$ cd test\ 7/

Another reason you might want to use programmable completion would be if you write script and want to be able to either list or complete options for you. This page has some really good example:

http://fahdshariff.blogspot.com/2011/04/writing-your-own-bash-completion.html

Here's an example:

Let's say I have a script called listanimals. I can write a completion function to assist with filling in the options

# complete sendevent
_listanimals()
{
    local cur=${COMP_WORDS[COMP_CWORD]}
    local prev=${COMP_WORDS[COMP_CWORD-1]}

    if [[ $prev == "--sort-direction" ]]; then
        COMPREPLY=( $( compgen -W "horizontal vertical" -- $cur ) )
        return 0
    elif [[ $prev == "--type" ]];then
        COMPREPLY=( $( compgen -W "mammals reptiles birds fish marsupials insects misc" -- $cur ) )
        return 0
    elif [[ $prev == "--size" ]]; then
        COMPREPLY=( $( compgen -W "tiny small medium large huge" -- $cur ) )
        return 0
    fi


    # completing an option
    if [[ "$cur" == --* ]] || [[ $cur == "" ]]; then
        COMPREPLY=( $( compgen -W "--sort-direction --type --size" -- $cur ) )
    fi
}
complete -F _listanimals listanimals

Now I can do this:

$ listanimals --[TAB][TAB]
--size            --sort-direction  --type
$ listanimals --t[TAB]

Which will automatically fill in this:

$ listanimals --type

Then I can do this:

$ listanimals --type [TAB][TAB]
birds       fish        insects     mammals     marsupials  misc        reptiles

And I'm sure you can figure out the rest. This is a working example so if you want to try it out just copy/paste it into a file (e.g. sample.sh) and source it in bash source sample.sh. You don't actually need to have a script named listanimals.

Hopefully someone will find this useful because I found it a pain to figure out.

Matthew
  • 6,351
  • 8
  • 40
  • 53