First, let me say, you'll probably find this tip a lot more usefull than my previous one, so... no special warning here!
I've written quite a few personnal bash completions and have realised that even if some completions can only be specific to one given command(to be really usefull), most of the time they're easy: they have to deal with easy stuff like short&long options optionally taking a parameter which itself can sometime be completed. So I wrote a generic, yet somewhat extensible, bash completion.
Once you have it installed, here is how you can start using it for your amazing new script:
Code: Select all
add_sgbc_for commandFor those wondering, there's no magic here, it just uses the help message provided it's sufficiently formated. And if you'd like to enjoy this completion for a tool which has no --help message or for which it is not formated right, you're _not_ out of luck, I'll show you below how you can probably make it to work anyway.
1 - install
First you have to put the file below in your bash_completion.d directory (usually /etc/bash_completion.d/ for gentoo or /usr/share/bash/completions/ for exherbo for system wide usage). I put the file here for hthe time being, but it should also be available in the post below.
Code: Select all
wget -O sgbc https://gitorious.org/sgbc/sgbc/blobs/raw/master/sgbcCode: Select all
sudo mv -v sgbc /etc/bash_completion.d/- it uses some functions of /etc/bash_completion (_get_comp_words_by_ref, _split_longopt and _filedir at least) so sgbc won't work if those function are not defined
- you'll probably have to source the file explicitly in your bashrc, or the completion won't be available
2 - usage
Once you've done step 1, manually source the file or launch a new shell to load the completion, then, suppose you want to start using it for the grep and ss commands, run the following:
Code: Select all
add_sgbc_for grep ss3 - quick overview on how it works
As already said it uses the help message of a command to generate the completion. This is a good thing if you're developping something: it forces you to really print _real_ informations in your help message;)
Here is an example:
Code: Select all
ss --help
Usage: ss [ OPTIONS ]
ss [ OPTIONS ] [ FILTER ]
-h, --help this message
-V, --version output version information
...snip...
-i, --info show internal TCP information
-s, --summary show socket usage summary
-4, --ipv4 display only IP version 4 sockets
-6, --ipv6 display only IP version 6 sockets
...snip...
-w, --raw display only RAW sockets
-x, --unix display only Unix domain sockets
-f, --family=FAMILY display sockets of type FAMILY
-A, --query=QUERY
QUERY := {all|inet|tcp|udp|raw|unix|packet|netlink}[,QUERY]
-F, --filter=FILE read filter information from FILE
FILTER := [ state TCP-STATE ] [ EXPRESSION ]
And more, in the example above, see the QUERY string?
Code: Select all
-A, --query=QUERYCode: Select all
-A, --query={all|inet|tcp|udp|raw|unix|packet|netlink}Code: Select all
ss -A raCode: Select all
ss --query=raCode: Select all
ss -A raw
# or
ss --query=raw4 - advanced usage
So, you've got this command
- which does not have the --help option but just -h, or
- which has a help message not formated right to be usable by sgbc(or a help message which could be improved as we'll see with the command 'ss' below) or
- which has no help message, but for which you could easily make one quickly(dynamicaly or not)
- ...
Let's say you have enabled sgbc for the command my-script.sh, _before_ trying to call my-script.sh --help, sgbc checks if the function __sgbc_myscriptsh_get_help exists and runs it instead if it does.
note: my-script.sh becomes myscriptsh by removing every character that's not in [A-Za-z0-9_]
So here is the real magic:
- you script does not have the --help option but the --show-help one? defined the following function(and add it to your bashrc if satisfaying)
Code: Select all
__sgbc_myscriptsh_get_help() { my-script.sh --show-help; } - the help message is poorly formated? may be you can reformat it using some sed/awk magic?
Code: Select all
__sgbc_myscriptsh_get_help() { # adapt the following to your needs! my-script.sh --help | sed -n 'G; x; ${x;p}' } - and so on! Your Imagination is your only limitation;)
Back to our ss example, I said, if instead of QUERY we had the possible values, it can take, enclosed in {} and separated with the pipe character, then sgbc will even be able to propose completion on the parameter. Let's do just that then!
By reading the manual, we learn that the possible values for QUERY are all, inet, tcp, udp, raw, unix, packet, netlink, unix_dgram, unix_stream, packet_raw, packet_dgram
note: from the manual, again, it looks like FAMILY is also restricted by the value it can take ( unix, inet, inet6, link, netlink)
Let's create the __sgbc_ss_get_help which will print an improved(sgbc speaking) help message:
Code: Select all
__sgbc_ss_get_help() {
ss --help | sed '/--[^[:space:]]\+=/ {
s/QUERY/{all|inet|tcp|udp|raw|unix|packet|netlink|unix_dgram|unix_stream|packet_raw|packet_dgram}/
s/FAMILY/{unix|inet|inet6|link|netlin}/
}'
}Code: Select all
__sgbc_ss_get_helpOnce you've defined this function in your active shell, you can already enjoy the improved completion on the parameter! That's right! nice isn't it?
If you try to format the help message, here is how it can look
Code: Select all
somecommand brief description
blablbbalbl
options can be like this
--long-option
-l, --long-option blahblahblah
-l, --long-option
and the same without the comma between the short and
the long option:
-l --long-option blahblahblah
but also with restricted parameter(listed in {} separated with |
--long-option={a|b|c} blahblahblah
-l, --long-option={a|b|c}
it also understand optional parameter even it the completion
really be optional
-l, --long-option[={a|b|c}] blahblahblah
if the parameter starts with a '/' it will try to complete on filenames:
which can sometimes be wrong (e.g. the --server=/domain/ option of dnsmasq)
-l, --long-option=/something blahblahblah
if the parameter doesn't look like the above, then there will be
no completion available on the parameter, but it will start again
on the next argument
-l, --long-option=/something blahblahblah
and a few more combinations of themThat's it for tonight, hope I haven't made to many typos in there!
Have fun!
EDIT: a few typos... and a trick to make you shell scripts handling --long-option=param _and_ --long-option param
EDIT: some improvements see below

