SSH Bash Completion
3 Comments Published June 30th, 2011 in Java, Linux, Unix Tags: Bash, completion, Git, howto, Linux, reference, unix.Today I was having a look on how the git-completition is implemented. If you have not enabled the completition for git, I think you should really read my article on how to do it.
So I found this two links, that explain the basics on how to implement bash completion for simple commands:
And I implemented my completion for ssh, which takes the hostnames from the file ~/.ssh/known_hosts
# Add bash completion for ssh: it tries to complete the host to which you
# want to connect from the list of the ones contained in ~/.ssh/known_hosts
__ssh_known_hosts() {
if [[ -f ~/.ssh/known_hosts ]]; then
cut -d " " -f1 ~/.ssh/known_hosts | cut -d "," -f1
fi
}
_ssh() {
local cur known_hosts
COMPREPLY=()
cur="${COMP_WORDS[COMP_CWORD]}"
known_hosts="$(__ssh_known_hosts)"
if [[ ! ${cur} == -* ]] ; then
COMPREPLY=( $(compgen -W "${known_hosts}" -- ${cur}) )
return 0
fi
}
complete -o bashdefault -o default -o nospace -F _ssh ssh 2>/dev/null \
|| complete -o default -o nospace -F _ssh ssh
To load it, save the above script into a file called ‘ssh-completion’ then add “source ssh-completion” in your ~/.profile or ~/.bashrc. Some Linux distributions offer a directory where you can deploy your completion scripts, for example debian should have them like /etc/bash-completion.d/foobar.bash.
Then go on the command line and type:
$ ssh [tab]
If everything went fine, you should see a list of servers to which you recently connected.
I don’t go in detail to explain the above script, since there are good tutorials around for this purpose, including the links I included before.
I only want to say that the ‘compgen’ is an internal bash command, used in the above script: what it does is taking a list of words (-W ${known_hosts} option) from which to try to complete a given partial word (in the above example the ${cur} variable, which is the word at the cursor).
Since completion is usually implemented with bash scripts, it’s good to keep handy a bash reference manual.
Scared of bash scripts?
I am. I continuously forget the syntax of loops and conditional expressions: I think that the bash language is quite obscure and counter-intuitive. So I guess that is also possible to implement completion as part of your program using your language of choice (Java in my case). You can implement a feature in your program that reads and analyzes the COMP_WORDS and COMP_CWORD environment variables, and generate the list of completion words, as the ‘compgen’ bash built-in command does. And, if your language allows it, set those words into the COMPREPLY environment variable; in Java I think it’s not possible to alter environment variables, but you can just output the words on the standard output and use a brief script to set that output to the COMPREPLY variable.
I’d suggest to bind this functionality to a ‘–completion’ option that can be specified in the command line, as we usually do for the –help option.
See git-completion.bash if you want an example of a complex completion script… bash can be hard.
Update
I just typed ‘complete’ on my mac, and I discovered I have 408 commands binded to some completion script. Including a more advanced ssh script which implements the hostname suggestions.
Search
Calendar
| M | T | W | T | F | S | S |
|---|---|---|---|---|---|---|
| « May | Jul » | |||||
| 1 | 2 | 3 | 4 | 5 | ||
| 6 | 7 | 8 | 9 | 10 | 11 | 12 |
| 13 | 14 | 15 | 16 | 17 | 18 | 19 |
| 20 | 21 | 22 | 23 | 24 | 25 | 26 |
| 27 | 28 | 29 | 30 | |||
Follow me
Archives
Categories
- Android (3)
- Apple (29)
- Books (7)
- Eclipse (14)
- Errors (5)
- Firefox (7)
- Git (3)
- Hardware (18)
- Horror Code (8)
- Internet (21)
- Java (104)
- JavaScript (9)
- Life, universe and everything (45)
- Lifehacks (26)
- Linux (52)
- Opinions (26)
- OSX (11)
- OWNER API (2)
- Python (1)
- Software (33)
- Speeches and Conferences (8)
- Unix (5)
- Web (23)
- Windows (19)
Tag Cloud
Android apple architecture Bash configuration CSS Development Düsseldorf Eclipse Git Google Hardware hdr How-To howto Java JAXB job Karmic Linux lion MacBook music Open Source Opinion OSX os x patterns Pitfalls Practices Resume Security Software Suspend TDD Testing tip tonemapped Tricks Ubuntu unix video Web Workaround XML
WP Cumulus Flash tag cloud by Roy Tanck and Luke Morton requires Flash Player 9 or better.
Blog License
Blogs I like
Books on the desk
Friends' Blogs
- Antonio Terreno & Valter Bernardini
- Bruno Bossola
- Daniele Galluccio
- Domenico Ventura
- Ed Schepis
- Fabrizio Gianneschi
- Luca Grulla
- Luigi Zanderighi
- Marcello Teodori
- Mida Boghetich
- Muralidharan Chandrasekaran
- Piero Ricca
- Renzo Borgatti
- Simone Bordet
- Simone Bruno
- Uberto Barbini
- Valvolog
- Webtide blogs (Greg Wilkins & Jan Bartel)
Links


















Hmm, SSH Bash completion based on known_hosts, I never thought of that. I have one based on ~/.ssh/config. (Let me know if you see any bugs.) I have more than 500 Host satements in my ~/.ssh.config.:
_ssh()
{
local cur prev hosts
COMPREPLY=()
cur=”${COMP_WORDS[COMP_CWORD]}”
prev=”${COMP_WORDS[COMP_CWORD-1]}”
#
# Complete the arguments based on Host lines in ~/.ssh/config
# All names on the Host line are added to the lookup glossary.
#
if [ -f $HOME/.ssh/config ]; then
hosts=$(grep “^Host ” $HOME/.ssh/config | awk ‘{for (i=2; i<=NF; i ) {print $i}}')
COMPREPLY=($(compgen -W "${hosts}" — ${cur}))
fi
}
# For scp, we add filename completion, the other commands just get hostname completion.
# (Only for bash)
if [ -n "$BASH_VERSION" ]; then
complete -f -F _ssh scp
complete -F _ssh host sftp ssh sshgr
fi
As you can see, I also use this for the host command. The sshgr script greps out stanzas from my ~/.ssh/config file that contain the host I'm curious about.
Additionally, Red Hat, CentOS, Fedora allow you to store profile modifications in /etc/profile.d/. I store the above as ssh-bash-completion.sh there.
Hi, if you change the if statement to this:
if [[ ! ${cur} == -* ]] ; then
if [[ ${cur} == *@* ]] ; then
COMPREPLY=( $(compgen -W “${known_hosts}” -P ${cur/@*/}@ — ${cur/*@/}) )
else
COMPREPLY=( $(compgen -W “${known_hosts}” — ${cur}) )
fi
fi
it works in the case of ssh user@host as well.
Thanks for writing this up, was very useful.
r.