https://www.tldp.org/LDP/abs/html/tabexpansion.html
and compgen builtins make it possible for tab completion to recognize partial parameters and options to commands. In a very simple case, we can use complete from the command-line to specify a short list of acceptable parameters.
bash$ touch sample_command bash$ touch file1.txt file2.txt file2.doc file30.txt file4.zzz bash$ chmod +x sample_command bash$ complete -f -X '!*.txt' sample_command bash$ ./sample[Tab][Tab] sample_command file1.txt file2.txt file30.txt |
The -f option to complete specifies filenames, and -X the filter pattern.
For anything more complex, we could write a script that specifies a list of acceptable command-line parameters. The compgen builtin expands a list of arguments to generate completion matches.
Let us take a modified version of the UseGetOpt.sh script as an example command. This script accepts a number of command-line parameters, preceded by either a single or double dash. And here is the corresponding completion script, by convention given a filename corresponding to its associated command.
Example J-1. Completion script for UseGetOpt.sh
https://stuff-things.net/2016/05/11/bash-autocompletion/# file: UseGetOpt-2 # UseGetOpt-2.sh parameter-completion _UseGetOpt-2 () # By convention, the function name { #+ starts with an underscore. local cur # Pointer to current completion word. # By convention, it's named "cur" but this isn't strictly necessary. COMPREPLY=() # Array variable storing the possible completions. cur=${COMP_WORDS[COMP_CWORD]} case "$cur" in -*) COMPREPLY=( $( compgen -W '-a -d -f -l -t -h --aoption --debug \ --file --log --test --help --' -- $cur ) );; # Generate the completion matches and load them into $COMPREPLY array. # xx) May add more cases here. # yy) # zz) esac return 0 } complete -F _UseGetOpt-2 -o filenames ./UseGetOpt-2.sh # ^^ ^^^^^^^^^^^^ Invokes the function _UseGetOpt-2. |
The command that setups autocompletion is
complete
. When giving it a list, pass them in as an augument to the -W
option:
I’m capturing the output of the command with
$()
and wrapping it in double quotes. The last argument is the name of the command (which can be also be a function or alias) that will use this autocompletion. Now we get this:
That works fine, but it’s static and applies only to one command. Instead you can create a reusable function.
BASH auto completion functions are powerful things, but for today we’re keeping it simple. First we build a list of options as before and store it in
$known_hosts
. Second we get the current word, the command argument, which is be tab completed. Finally, we pass that list and that word into compgen
which is BASH’s internal matcher. compgen
has some powerful features, but in this case it’s just going to return a list of hosts in $known_hosts
that start with the word we hit tab on.
Then we tell the completion that we are using a function by giving it the
-f
option, along with the function name, instead of -W
:
And you can use the
_known_hosts
function for other commands as well:
This is a good exercise in understanding autocompletion, but it’s pretty basic. Fortunately, people have already done all of the hard work in the bash-completion project. This ships by default with many Linux distros. On the Mac:
The add:
For example, given the following
hosts(5)
file in place at /etc/hosts
:127.0.0.1 localhost
192.0.2.1 web.example.com www
198.51.100.10 mail.example.com mx
203.0.113.52 radius.example.com rad
An appropriate call to
compgen
would yield this output:$ compgen -A hostname
We could then use this to complete hostnames for network diagnostic tools like
ping(8)
:$ complete -A hostname ping
There’s a simple way to make host completion much more useful by defining the HOSTFILE
variable in ~/.bashrc
to point to any other file containing a list of hostnames. You could, for example, create a simple file ~/.hosts
in your home directory, and then include this in your ~/.bashrc
:
# Use a private mock hosts(5) file for completion
HOSTFILE=$HOME/.hosts
This setup allows you to set hostname completion as the default method for all sorts of network-poking tools, falling back on the usual filename completion if nothing matches with -o default
:
$ complete -A hostname -o default curl dig host netcat ping telnet