54

When I ssh into a remote production server I would like the colour scheme of my terminal window to change to something brigh and scary, preferably red, to warn me that I am touching a live scary server.

How can I make it automatically detect that I have ssh'ed somewhere, and if that somewhere is on a specific list, change the colour scheme?

I want to update the Scheme of Terminal.app, not know how I would do this in a pure linux/unix env

Lebyrt
  • 1,376
  • 1
  • 9
  • 18
Laurie Young
  • 136,234
  • 13
  • 47
  • 54
  • Why is a pure linux/unix solution bad? – Milhous Oct 01 '08 at 19:30
  • 2
    @Milhous Because OS X's Terminal.app offers far more style customizations than the *nix-based customizations do, from font & ANSI colors to line & character spacing to background color, opacity, & blur. Terminal's styles look really good when adjusted tastefully, and many of us OS X users like our computers to look like they're from the 2010s, not the 1980s. – Slipp D. Thompson Jul 14 '15 at 19:51

11 Answers11

54

Put following script in ~/bin/ssh (ensure ~/bin/ is checked before /usr/bin/ in your PATH):

#!/bin/sh

HOSTNAME=`echo $@ | sed s/.*@//`

set_bg () {
  osascript -e "tell application \"Terminal\" to set background color of window 1 to $1"
}

on_exit () {
  set_bg "{0, 0, 0, 50000}"
}
trap on_exit EXIT

case $HOSTNAME in
  production1|production2|production3) set_bg "{45000, 0, 0, 50000}" ;;
  *) set_bg "{0, 45000, 0, 50000}" ;;
esac

/usr/bin/ssh "$@"

Remember to make the script executable by running chmod +x ~/bin/ssh

The script above extracts host name from line "username@host" (it assumes you login to remote hosts with "ssh user@host").

Then depending on host name it either sets red background (for production servers) or green background (for all other). As a result all your ssh windows will be with colored background.

I assume here your default background is black, so script reverts the background color back to black when you logout from remote server (see "trap on_exit").

Please, note however this script does not track chain of ssh logins from one host to another. As a result the background will be green in case you login to testing server first, then login to production from it.

dade
  • 3,340
  • 4
  • 32
  • 53
Yurii Soldak
  • 1,458
  • 4
  • 19
  • 24
39

A lesser-known feature of Terminal is that you can set the name of a settings profile to a command name and it will select that profile when you create a new terminal via either Shell > New Command… or Shell > New Remote Connection….

For example, duplicate your default profile, name it “ssh” and set its background color to red. Then use New Command… to run ssh host.example.com.

It also matches on arguments, so you can have it choose different settings for different remote hosts, for example.

Chris Page
  • 18,263
  • 4
  • 39
  • 47
  • 4
    I can't believe how useful this is. Just the thing I was looking for. – Pascal Feb 22 '14 at 19:43
  • 6
    This is the best answer for me. of note, the profile name can be a regex, e.g. 'ssh .*myserver.*' is matching 'ssh myserver', 'ssh -p 22 myserver.foo.com' etc. – robm Jan 09 '15 at 09:49
  • Works great on Sierra. Trying to figure out now if I can shortcut the ssh somewhere instead of having to open New Remote Connection each time – George Mar 10 '18 at 22:40
  • unfortunately this leaves the colour set after the SSH session ends (e.g. if terminal reopens windows after a reboot, or the connection drops). – Dan W Oct 06 '20 at 10:03
10

Another solution is to set the colors straight in the ssh config file:

inside ~/.ssh/config

Host Server1
   HostName x.x.x.x
   User ubuntu
   IdentityFile ~/Desktop/keys/1.pem
   PermitLocalCommand yes
   LocalCommand osascript -e "tell application \"Terminal\" to set background color of window 1 to {27655, 0, 0, -16373}"

Host Server2
   HostName x.x.x.x
   User ubuntu
   IdentityFile ~/Desktop/keys/2.pem
   PermitLocalCommand yes
   LocalCommand osascript -e "tell application \"Terminal\" to set background color of window 1 to {37655, 0, 0, -16373}"
orion elenzil
  • 4,484
  • 3
  • 37
  • 49
arnon cohen
  • 485
  • 1
  • 5
  • 15
  • This should be the accepted answer. Far and away the simplest. – Bob Woodley Aug 07 '18 at 18:47
  • 3
    The problem with this solution is that it doesn't change the colour back once you exit the ssh session. However I have managed to overcome this limitation by using a simple tool: https://github.com/drinchev/phook. This is my line in `~/.ssh/config`: `LocalCommand phook -a "osascript -e 'tell application \"Terminal\" to set current settings of window 1 to settings set \"Basic\"'" -e "osascript -e 'tell application \"Terminal\" to set current settings of window 1 to settings set \"SSH-Yellow\"'"` – Kuba Wyrostek Jan 03 '19 at 12:29
9

Here's a combined solution based on a couple of existing answers that handles the exit. Also includes a little extra if you don't want to deal with 16 bit color values.

This should be put in your ~/.bash_profile

# Convert 8 bit r,g,b,a (0-255) to 16 bit r,g,b,a (0-65535)
# to set terminal background.
# r, g, b, a values default to 255
set_bg () {
    r=${1:-255}
    g=${2:-255}
    b=${3:-255}
    a=${4:-255}

    r=$(($r * 256 + $r))
    g=$(($g * 256 + $g))
    b=$(($b * 256 + $b))
    a=$(($a * 256 + $a))

    osascript -e "tell application \"Terminal\" to set background color of window 1 to {$r, $g, $b, $a}"
}

# Set terminal background based on hex rgba values
# r,g,b,a default to FF
set_bg_from_hex() {
    r=${1:-FF}
    g=${2:-FF}
    b=${3:-FF}
    a=${4:-FF}

    set_bg $((16#$r)) $((16#$g)) $((16#$b)) $((16#$s))
}

# Wrapping ssh command with extra functionality
ssh() {
    # If prod server of interest, change bg color
    if ...some check for server list
    then
        set_bg_from_hex 6A 05 0C
    end

    # Call original ssh command
    if command ssh "$@"
    then
        # on exit change back to your default
        set_bg_from_hex 24 34 52
    fi
}
  • set_bg - takes 4 (8 bit) color values
  • set_bg_from_hex - takes 4 hex values. most of my color references I use are in hex, so this just makes it easier for me. It could be taken a step further to actually parse #RRGGBB instead of RR GG BB, but it works well for me.
  • ssh - wrapping the default ssh command with whatever custom logic you want. The if statement is used to handle the exit to reset the background color.
bingles
  • 11,582
  • 10
  • 82
  • 93
  • you can use `osascript -e "tell application \"Terminal\" to get background color of window 1"` to get the original colors (in decimal) – AlexChaffee Dec 11 '15 at 17:17
8

Combining answers 1 and 2 have the following:

Create ~/bin/ssh file as described in 1 with the following content:

#!/bin/sh
# https://stackoverflow.com/a/39489571/1024794
log(){
  echo "$*" >> /tmp/ssh.log
}
HOSTNAME=`echo $@ | sed s/.*@//`
log HOSTNAME=$HOSTNAME
# to avoid changing color for commands like `ssh user@host "some bash script"`
# and to avoid changing color for `git push` command:
if [ $# -gt 3 ] || [[ "$HOSTNAME" = *"git-receive-pack"* ]]; then
  /usr/bin/ssh "$@"
  exit $? 
fi

set_bg () {
  if [ "$1" != "Basic" ]; then
    trap on_exit EXIT;
  fi
  osascript ~/Dropbox/macCommands/StyleTerm.scpt "$1"
}

on_exit () {
  set_bg Basic
}


case $HOSTNAME in
  "178.222.333.44 -p 2222") set_bg "Homebrew" ;;
  "178.222.333.44 -p 22") set_bg "Ocean" ;;
  "192.168.214.111") set_bg "Novel" ;;
  *) set_bg "Grass" ;;
esac

/usr/bin/ssh "$@"

Make it executable: chmod +x ~/bin/ssh.

File ~/Dropbox/macCommands/StyleTerm.scpt has the following content:

#https://superuser.com/a/209920/195425
on run argv
  tell application "Terminal" to set current settings of selected tab of front window to first settings set whose name is (item 1 of argv)
end run

Words Basic, Homebrew, Ocean, Novel, Grass are from mac os terminal settings cmd,: terminal profiles

Community
  • 1
  • 1
Maxim Yefremov
  • 13,671
  • 27
  • 117
  • 166
5

You can set the $PS1 variable in your .bashrc.

red='\e[0;31m'
PS1="$\[${red}\]"

EDIT: To do this open the Terminal. Then say

#touch .bashrc

You can then open .bashrc in textEdit or in TextWrangler and add the previous commands.

Milhous
  • 14,473
  • 16
  • 63
  • 82
4

Set the terminal colours in the server's /.bashrc

I needed the same thing, something to make me aware that I was on a Staging or Production server and not in my Development environment, which can be very hard to tell, especially when in a Ruby console or something.

To accomplish this, I used the setterm command in my server's ~./bashrc file to inverse the colours of the terminal when connecting and restore the colours when exiting.

~/.bashrc

# Inverts console colours so that we know that we are in a remote server. 
# This is very important to avoid running commands on the server by accident.
setterm --inversescreen on

# This ensures we restore the console colours after exiting.
function restore_screen_colours {
  setterm --inversescreen off
}
trap restore_screen_colours EXIT

I then put this in all the servers' ~/.bashrc files so that I know when my terminal is on a remote server or not.

Another bonus is that any of your development or devops team get the benefit of this without making it part of the onboarding process.

Works great.

Joshua Pinter
  • 45,245
  • 23
  • 243
  • 245
2

Xterm-compatible Unix terminals have standard escape sequences for setting the background and foreground colors. I'm not sure if Terminal.app shares them; it should.

case $HOSTNAME in
    live1|live2|live3) echo -e '\e]11;1\a' ;;
    testing1|testing2) echo -e '\e]11;2\a' ;;
esac

The second number specifies the desired color. 0=default, 1=red, 2=green, etc. So this snippet, when put in a shared .bashrc, will give you a red background on live servers and a green background on testing ones. You should also add something like this to reset the background when you log out.

on_exit () {
    echo -e '\e]11;0\a'
}
trap on_exit EXIT

EDIT: Google turned up a way to set the background color using AppleScript. Obviously, this only works when run on the same machine as Terminal.app. You can work around that with a couple wrapper functions:

set_bg_color () {
    # color values are in '{R, G, B, A}' format, all 16-bit unsigned integers (0-65535)
    osascript -e "tell application \"Terminal\" to set background color of window 1 to $1"
}

sshl () {
    set_bg_color "{45000, 0, 0, 50000}"
    ssh "$@"
    set_bg_color "{0, 0, 0, 50000}"
}

You'd need to remember to run sshl instead of ssh when connecting to a live server. Another option is to write a wrapper function for ssh that scans its arguments for known live hostnames and sets the background accordingly.

skymt
  • 3,199
  • 21
  • 13
1

Why not just changing the shell prompt whenever you are logged in via SSH? There are usually specific shell variables: SSH_CLIENT, SSH_CONNECTION, SSH_TTY

unexist
  • 2,518
  • 23
  • 27
0

You should change the color of username and host machine name.

add the following line to your ~/.bash_profile file:

export PS1=" \[\033[34m\]\u@\h \[\033[33m\]\w\[\033[31m\]\[\033[00m\] $ "

The first part (purple colored) is what you're looking for.

Preview: enter image description here

This is my preferred colors. You can customize each part of prompt's color by changing m codes (e.g. 34m) which are ANSI color codes.

List of ANSI Color codes:

  • Black: 30m
  • Red: 31m
  • Green: 32m
  • Yellow: 33m
  • Blue: 34m
  • Purple: 35m
  • Cyan: 36m
  • White: 37m
Shayan Amani
  • 5,787
  • 1
  • 39
  • 40
0

All the applescript-based answers I've seen on the SO family suffer a reliance on Terminal's "Window 1", which is the currently focused window. The problem is that if your ssh session closes while you've got a different window focused, the message gets sent to the wrong window.

Using this answer to a question of mine, I'm finding the following approach to be much more robust in the face of remote disconnect.

##########################################################################################################
# MacOS: sets the visual profile of the terminal window to a particular color while SSH'ing into another host.
# usage:
# 1. set up a terminal profile named "ssh_remote"  which is how you'd like the window to appear when ssh'd.
# 2. set up a terminal profile named "ssh_local"   which is how you'd like the window to appear when not ssh'd.
# Thanks to @Philippe on S.O. for help with osascript. https://stackoverflow.com/a/76443239/230851
function ssh() {
    osascript -e 'tell application "Terminal" to set current settings of (the first window whose tty of tab 1 contains "'"$(tty)"'") to settings set "ssh_remote"'
    command ssh "$@"
    osascript -e 'tell application "Terminal" to set current settings of (the first window whose tty of tab 1 contains "'"$(tty)"'") to settings set "ssh_local"'
}
orion elenzil
  • 4,484
  • 3
  • 37
  • 49