(Even More) Advanced Bash Completion

In my previous post, I described how to set up tab completion for many common commands using these Bash completion files. This works well for established commands, but it doesn’t work so well for commands that I have written myself.

I use a command called “hc12-console” to connect to 68HC12 microcontrollers over a serial port. The command takes two arguments: the name of a microcontroller to connect to and a file to load. I only have two microcontrollers called “dragon1” and “dragon2”. Therefore, I want to be able to tab complete the first argument to one of those values only. The second argument should be the name of a file that ends in “.load”.

I do this with a function that checks the argument number and then completes it based on a specified list or by limiting the types of files that will be listed.

_hc12console ()
{
	local cur

	COMPREPLY=()
	cur=${COMP_WORDS[COMP_CWORD]}

	# First argument completes with either dragon1 or dragon2
	if [[ $COMP_CWORD -eq 1 ]] ; then
		COMPREPLY=( $( compgen -W "dragon1 dragon2" -- $cur ) )
		return 0
	fi

	# Second argument completes with only files matching *.load
	if [[ $COMP_CWORD -eq 2 ]] ; then
		COMPREPLY=( $( compgen -f -X '!*.load' -- $cur ) )
		return 0
	fi

	# All other arguments will not auto-complete
	return 0
}
complete -F _hc12console hc12-console

I added the script above to a file that my bashrc sources. It associates the function with the shell command, and then instead of manually typing out:

hc12-console dragon1 file.load <enter>

I can type:

hc12<tab> <tab>1 <tab> <enter>

Advanced Bash Completion

Ubuntu has a lot of advanced bash completion features that simplify using the shell. For example, when using the ssh command, I can tab complete server names based on my host file and my ssh config file. It turns out that most of this is accomplished with one bash_completion script. This page has a lot of useful information about the Bash shell and also the very useful script. I’ve found that when I use Fedora in the Xinu lab, I am left typing a lot of this stuff myself. Since I use the same bashrc file on both Dakara and my lab machine (Kastria), I didn’t want to always resource the file so I added this to my bashrc:

# Source global definitions
[ -f /etc/bashrc ]      && source /etc/bashrc
[ -f /etc/bash.bashrc ] && source /etc/bash.bashrc
# enable programmable completion features
if [ -z "$BASH_COMPLETION" \
    -a -r ~/.configuration/bash/bash_completion.caliban ]; then
    BASH_COMPLETION=~/.configuration/bash/bash_completion.caliban
    source $BASH_COMPLETION
fi

First, I source the global definitions, Ubuntu uses /etc/bashrc, and Fedora uses /etc/bash.bashrc. After that, if the bash_completion script was already sourced, $BASH_COMPLETION will be set. I check to see if it is zero length (-z) and then source my own copy of it if it is. Now I have advanced bash completion on both Ubuntu and Fedora.