Wednesday, May 7, 2008

bash: completion

Almost everybody uses bash. It's awesome with it simplicity and power. Recently I've been introduced to bash completion in conjunction with ssh. The author proposed to use bash completion to expand list of known hosts(~/.ssh/known_hosts) for ssh. He suggested to fetch the list and feed it to 'complete' built-in bash command:

complete -W "`cat ~/.ssh/known_hosts \
| cut -d ' ' -f1 | cut -d ',' -f1 | cut -d ']' -f1 \
| sed 's/\[//' | sort`" ssh
This command will provide a fixed list. If you eventually have gone to the new host the new hostname will be lost for the completion. I've made some investigation and have found out that you can provide a function for 'complete' that will be called each time the completion requested. Here is a function:
function _ssh_comp()
{
CUR="${COMP_WORDS[COMP_CWORD]}";
COMPREPLY=( $(compgen -W "$(gawk 'BEGIN {i=0}\
{split($1,nodes,",");\
gsub("([[]|[]]:?[0-9]*)","",nodes[1]);\
hosts[i++]=nodes[1]}\
END {for (j in hosts) {print hosts[j]}}' ~/.ssh/known_hosts)" -- ${CUR}) );
return 0;
}
From the bash reference:
We can read the description of COMPREPLY
An array variable from which Bash reads the possible completions generated by a shell function invoked by the programmable completion facility
We can also see how we found the current word using the array COMP_WORDS to find both the current and the previous word by looking them up
An array variable consisting of the individual words in the current command line. This variable is available only in shell functions invoked by the programmable completion facilities.
COMP_CWORD
An index into ${COMP_WORDS} of the word containing the current cursor position. This variable is available only in shell functions invoked by the programmable completion facilities
Then you should tell 'complete' to use this function:
complete -o default -F _ssh_comp ssh
I typed 'ssh 1' then pressed and here we go:
$ssh 192.168.229.1
192.168.229.128  192.168.229.130  192.168.229.132  192.168.229.134  192.168.229.137  192.168.229.140  192.168.229.145  
192.168.229.129  192.168.229.131  192.168.229.133  192.168.229.136  192.168.229.138  192.168.229.144  192.168.229.146

No comments: