Use ssh comfortably with command history and auto-complete

ssh_autocompleteWhen using ssh on a daily basis you type a lot, given you are probably entering a lot of hostnames and command-line options. But on your local Linux or OS X powered computer you have a lot of powerful tools to make your life easier. I would like to show a couple of easy tricks to make your life easier while working with ssh.

Imagine the situation where you connect to ssh servers a lot of times during the day. If you know these servers and use them over and over again, you will find yourself typing commands like this over and over again.

$ ssh username@hostname.example-domain.com

Depending on the username and hostname of the servers you connect to, that can be a lot of typing. If you have a couple of options involved in the connection (like port forwarding), you type even more.

Navigate the history

You most likely already know about your command history. You navigate the it the easiest way with your cursor keys. But if you have already executed a lot of shell commands since you have executed the desired ssh command, navigating with the cursor keys can be a pain.

The faster way of finding your ssh command in a huge bash history is by using the reverse-search. This search can be started by hitting the CTRL+R key combination. As a result you will see the following instead of your regular prompt.

(reverse-i-search)`': 

This new prompt will now accept your search string. Just type ssh to find the last ssh command you typed. If it is not the one you are looking for, don’t use the cursor keys to navigate the results, but press CTRL+R to see the next result. Each time you press CTRL+R you will search backwards through your history. A result of such a reverse search might look similar to the following example.

(reverse-i-search)`ssh': ssh username@hostname.example-domain.com -L 12345:127.0.0.1:12345

You can see here the search term between the two different quotes (`ssh’) and after the colon the command found in the history. If ssh is not enough to look the command up, you could instead type “hostname” to find this command.

If you do not want to execute the command as it is shown, just use the cursor left/right keys to navigate through the command line as you do normally. As soon as you use the cursor keys, you fall out of the reverse-search prompt back to your normal prompt and you can edit the command right before executing it.

Basically you can search for any string that is inside the command line, as this history lookup is a bash – not ssh – feature.

Bash even allows you to add a comment onto a command-line which remains even in the history, allowing you to search for it. The following command shows how the comment is added to the command-line.

$ ssh username@hostname.example-domain.com # important command

The comment added to the command-line, started with the “#” (hash) character, does not have any influence on the execution of the command but it will stay in the history with it. You can now find the command in the history by the comment as well as any other part of the command.

Configure the ssh client

If you have a lot of servers you connect to on a regular basis, reverse-search by itself might not make your life much easier, but with the proper configuration of the ssh client, you can give yourself some more help.

The ssh client program has its own configuration file which is placed in your user’s home directory. The “.ssh” directory in your home folder is probably familiar from the SSH passwordless login with SSH key. Within this directory the configuration for the ssh client is stored. By default, the directory is initially empty and gets populated with the “known_hosts” file that contains identification of the ssh hosts you have connected to.

With the following command we will create an “.ssh/config” file that will contain additional configuration options for the ssh client.

$ vim ~/.ssh/config

I used “vim” as editor but feel free to use the editor of your choice to create the file and add the configuration. The config file provides a lot of configuration options which I will not describe all of here, but I would like to give you 2 configuration examples.

Host host1 host1.example-domain.com
    Port 1234
    User username
    HostName host1.example-domain.com
    IdentityFile ~/.ssh/user_host.example-domain.com_key-rsa
    LocalForward 8080 127.0.0.1:80
    LogLevel DEBUG1

Host *.example.com
    Port 1234
    User username
    IdentityFile ~/.ssh/user_host.example.com_key-rsa
    LogLevel QUIET

This config file shows 2 sections starting with the “Host ” line. They define for which host they are used. you can define here whatever name you wish to use in your ssh command. With this configuration the following 2 commands will connect to exactly the same ssh server with the same configuration.

$ ssh host1
$ ssh host1.example-domain.com

Both of them will be covered by the first “Host ” section. The second host section would apply for every hostname that ends with “.example.com”. This can be handy if you want to set the same configuration for a list of ssh servers under the same domain.

Each of the Host sections have their own configuration items. These may contain the hostname, username, the ssh-key file as well as the port-forwarding configuration just to name a few. With this configuration you don’t need to provide the related command line options when you connect. Lets assume the first Host configuration would all need to be provided in the command line. That would look like this:

$ ssh username@host1.example-domain.com -p 1234 -v -i ~/.ssh/user_host.example-domain.com_key-rsa -L 8080:127.0.0.1:80

This is quite a long command to type, but with the configuration we have created in the ~/.ssh/config file, you can do the same just with “ssh host1”.

Autocomplete for ssh host names

As a Linux user you will be familiar with the auto-complete feature. When you start typing a command and press the tab-key twice, it will complete the command or you get a list of possible commands and when you press the tab-key twice after the command you get the files of the current directory to auto complete. Working with auto-complete makes it much easier and faster to work in the shell, and you can also use this to complete your host names.

You can define a so-called word list that the auto-complete will offer you with the following command. The -o options define that you want to see the files and directories of the current directory as well as the file list. This is especially important when you configure the auto-complete of scp as here in the example.

$ complete -o plusdirs -o filenames -W "host1 host1.example-domain.com" ssh scp 

After you have executed this, the shell’s auto-complete will offer you additionally to the files and directories the two words we have specified. So when you enter “ssh” and press the tab-key twice you should see something similar to this.

$ ssh 
.gnupg/                   host1.example-domain.com
host1                     .ssh/

If you have a lot of different hosts configured, you don’t want to create this “complete” command every time you change something in your config file. The idea is to load the auto-complete list when you open the shell. The shell opens its configuration file when it gets started. One of the configuration files is the “.profile” file in the user’s home directory. Within this file you can define a lot of the shell’s behaviour. Beside a lot of other things you can call the “complete” command to load the word-list.

$ vim ~/.profile

After you have opened the “.profile” file you can add the command as above and statically add the host names to it, but you can also add them automatically by reading it out of the ~/.ssh/config file. When you add the following lines into the .profile, it will read the config file and generate the word list from it. This word list is then passed on to the “complete” command.

# Autocomplete ssh commands
WL="$(perl -ne 'print "$1\n" if /^Host (.+)$/' ~/.ssh/config | grep -v "*" | tr "\n" " ")"
complete -o plusdirs -f -W "$WL" ssh scp

While it reads the ~/.ssh/config file for host names, it will remove all hostnames that start with a “*” as those are not useful in the auto-complete. After you have changed the “.profile” file the changes are not loaded automatically. You need to logout and login again to load them or reload the configuration file with the following command.

$ . ~/.profile

This will cause the .profile configuration to be loaded so you can start using the configured auto-complete options.


Read more of my posts on my blog at http://blog.tinned-software.net/.

This entry was posted in Linux Administration and tagged , , . Bookmark the permalink.