Friday, March 18, 2011

My Bash Profile - Part III: Completions

Bash programmable completion is a powerful feature which allows you to specify how arguments to commands should be completed. You do this using the complete command. For example, you can set completion up so that when you type the unzip command and hit the TAB key, it only shows completions for files ending with the .zip extension. Similarly, the completion for the ssh command would display hosts taken from your known_hosts file.

The completion file I use can be downloaded from here and saved in ~/.bash_completion. It has a comprehensive range of completions covering commands such as java, cvs, ant, make and kill.

Update: My dotfiles are now in Git. For the latest version, please visit my GitHub dotfiles repository.

One of my favourites is shown below:

_longopt is a generic completion function which can be used to complete the options on a number of different commands. For example, if you type grep --[TAB] you will see the available options for grep.

_longopt()
{
  local cur opt
  cur=${COMP_WORDS[COMP_CWORD]}

  if [[ "$cur" == --*=* ]]; then
      opt=${cur%%=*}
      # cut backslash that gets inserted before '=' sign
      opt=${opt%\\*}
      cur=${cur#*=}
      _filedir
      COMPREPLY=( $( compgen -P "$opt=" -W '${COMPREPLY[@]}' -- $cur))
      return 0
  fi

  if [[ "$cur" == -* ]]; then
      COMPREPLY=( $( $1 --help 2>&1 | sed -e '/--/!d' \
        -e 's/.*\(--[-A-Za-z0-9]\+=\?\).*/\1/' | \
        command grep "^$cur" | sort -u ) )
  fi
}
for i in a2ps autoconf automake bc gprof ld nm objcopy objdump readelf strip \
  bison cpio diff patch enscript cp df dir du ln ls mkfifo mknod mv rm \
  touch vdir awk gperf grep grub indent less m4 sed shar date \
  tee who texindex cat csplit cut expand fmt fold head \
  md5sum nl od paste pr ptx sha1sum sort split tac tail tr unexpand \
  uniq wc ldd bash id irb mkdir rmdir; do
  complete -F _longopt $i
done
Here is a demo:
sharfah@starship:~> grep --[TAB][TAB]
--after-context=       --color                --exclude-from=
--basic-regexp         --colour               --exclude=
--before-context=      --context=             --extended-regexp
--binary               --count                --file=
--binary-files=        --devices=             --files-with-matches
--byte-offset          --directories=         --files-without-match

More posts on my Bash profile:

3 comments:

  1. This comment has been removed by the author.

    ReplyDelete
  2. Nice function, thanks!
    BTW, the 'fi' is missing for the second 'if'.

    ReplyDelete