Skip to content
← Back to all posts

Useful bash scripts: Automatically changing terminal theme when using ssh on macOS

31 May 2019

Written by 


A photograph of Nadeem Shabir

Nadeem Shabir
Automation Lead


But we are hackers and hackers have black terminals with green font colors ~ John Nunemaker

This is the second in a series of posts on useful bash aliases and shell customisations that developers here at Talis use for their own personal productivity. In this post I describe how I configured my shell to automatically change my terminal theme when I connect to a remote machine in any of our AWS accounts.


Background

As I’ve mentioned previously, at Talis, we run most of our infrastructure on AWS. This is spread over multiple accounts, which exist to separate our production infrastructure from development/staging infrastructure. Consequently we can find ourselves needing to SSH onto boxes across these various accounts. For me it is not uncommon to be connected to multiple machines across these accounts, and what I found myself needing was a way to quickly tell which of these were production boxes and which were servers in our development account.

Solution

All of my development work is done on a Macbook Pro running macOS. Several years ago I started using iTerm2 as my terminal emulator instead of the built in terminal which has always felt particularly limited. Given these constraints the solution I came up with was to implement a wrapper around an ssh command that would tell iTerm2 when to switch themes so that we can use different colors for production environments vs development.

#!/bin/bash

# Simple script that switches your iTerm2 Profile when using ssh.
# You'll need to export three environment variables:
# - SSH_DEFAULT_THEME
# - SSH_DANGER_THEME
# - SSH_WARNING_THEME
#
# The values for these must correspond exactly to the name of an iTerm Profile you have
# created. Within the Profile you can set the color/themes you wish to use.
#
# The script parses the hostname out of the ssh connection string (naive) and
# uses this in a case statement to set the theme. Add as many cases as you like.
#
# I've updated this recently to take advantage of iTerm's Badges feature to watermark
# my terminal session with the hostname. That way I can always tell what each session is
# connected to. For this to work I've inlined the iterm2_set_user_var function from
# the iterm shell integrations collection of tools.
#
# To use this either put this script or a symlink to it into /usr/local/bin
#
# author: ns@talis.com
# Github: kiyanwang

containsElement () {
  local e match="$1"
  shift
  for e; do [[ "$e" == "$match" ]] && return 0; done
  return 1
}

iterm2_set_user_var () {
  printf "\033]1337;SetUserVar=%s=%s\007" "$1" $(printf "%s" "$2" | base64 | tr -d '\n')
}

change_profile () {
  NAME=$1; if [ -z "$NAME" ]; then NAME="$SSH_DEFAULT_THEME"; fi
  #echo "Setting theme to $NAME"
  echo -e "\033]50;SetProfile=$NAME\a"
  iterm2_set_user_var current_ssh_host "$HOSTNAME"
}

on_exit () {
  change_profile
  iterm2_set_user_var current_ssh_host ""
}
trap on_exit EXIT

source ~/.aliases # awslookup is defined here

HOSTNAME=`echo $@ | sed s/.*@//`
PRODUCTION_EC2_HOSTS=(`awslookup production '*' text | awk -F'\t' '{ print $2"\n"$3 }'`)
STAGING_EC2_HOSTS=(`awslookup staging '*' text | awk -F'\t' '{ print $2 }'`)

if containsElement "$HOSTNAME" "${PRODUCTION_EC2_HOSTS[@]}"; then
  change_profile "$SSH_DANGER_THEME"
elif containsElement "$HOSTNAME" "${STAGING_EC2_HOSTS[@]}"; then
  change_profile "$SSH_WARNING_THEME"
else
  case $HOSTNAME in # use this block to add any additional hosts
    *.talisaspire.com) change_profile "$SSH_DANGER_THEME" ;;
    *.talis.com) change_profile "$SSH_DANGER_THEME" ;;
  esac
fi

echo "Connecting to $HOSTNAME"

/usr/bin/ssh "$@"

In order to work it requires you to create three profiles in iTerm2, and for the purposes of this each of these profiles is essentially the theme you want to use. When creating a profile you can customise colors, fonts etc. But crucially for each of them you need to enter a value in the badge field. This tells iTerm2 what to set as the badge, which is displayed as a watermark on the terminal. In this case I wanted to use the host of the machine that I’ve connected to which I specify as current_user_host in my script; therefore the value for the badge field needs to be set to \(user.current_ssh_host).

iTerm profile

When you’ve created the profiles you can add the following to your ~/.aliases file to ensure that the ssh wrapper script knows which profiles to use for the three themes it requires.

export SSH_DEFAULT_THEME=Spacemacs
export SSH_DANGER_THEME=Production
export SSH_WARNING_THEME=Staging

Once this is done you can use the wrapper script. Do the following:

  • copy the contents of the script to /usr/local/bin/ssh (or anywhere as long as it’s on your PATH)
  • now when you issue an ssh command in the terminal the script captures the hostname of the machine that you are trying to connect to
  • it then uses awslookup to check to see which AWS account that host resides in.
  • in my case, if it’s in the production account it tells iTerm to switch to the SSH_DANGER_THEME, and if it’s in our development account it uses the SSH_WARNING_THEME.
  • the terminal will then switch to the corresponding theme.
  • when you exit your ssh session the wrapper resets the theme back to your default.

For example, when I ssh to a production server, my terminal automatically switches to this:

Danger Theme

And when I connect to a development server, it automatically changes to this:

Warning Theme

As soon as I exit the ssh session the terminal is restored to my default theme.

Whilst this is a very specific solution for macOS you can achieve similar results on Linux. Enjoy!