Pragmatism in the real world

Changing OS X Terminal colours when ssh'ing into a server

I recently discovered that iTerm has bookmarks so you can set up a bookmark to ssh into a server and change the colours of the window. This makes it easy to remember which terminal window is for which server.

Thinking about it, I wondered if you could change the colours of the standard OS X Terminal via AppleScript. Inpired by Red Sweater’s Random Color Terminal post, I wrote some code to automatically change the Terminal colour whenever I ssh into a known server.

As I know PHP and PHP is installed on OS X, I used that :)

The key to controlling AppleScript via PHP is the osascript command line application. The code I need specifically is:


system("osascript -e 'tell application "Terminal"
set targetWindow to window 1
set background color of targetWindow to {" . $bgColour . "}
set cursor color of targetWindow to {" . $fgColour . "}
set normal text color of targetWindow to {" . $fgColour . "}
set bold text color of targetWindow to {" . $fgColour . "}
end tell' ");

where $bgColour and $fgColour are comma separated strings containing three numbers between 0 and 65535 as AppleScript colours are 16 bit.

We start by getting a command line solution where we can type:
termcolour.php white
or
termcolour.php 00ff00
or
termcolour.php 255 0 0

and have the background colour of the Terminal change to the colour we have asked for.

TerminalColour class

Firstly we need a class that can change the colour of the Terminal window for us and also translate colours from 8bit RGB to 16bit RGB. As it is also useful to be able to specify colours by name, eg. “white”, we’ll add a lookup system too. I store this in /usr/local/bin.

This class is quite long, so this is a snippet:

<?php
class TerminalColour
{
protected $_colour = array('255','255','255');

/**
* List of colours
*/
protected $_colours = array(
'white' => 'ffffff',
'black' => '000000',
// etc
);

/**
* Set the colour of the topmost Terminal window using AppleScript
*
* $bgColour may be either an array of red, green, blue (8 bit) or a
* hex string or a string that matches an entry in the _colours lookup
* list.
*
* If $fgColour is null, then automatically use either black or
* white based on brightness of $bgColour.
*
* @param array|string $bgColour
* @param array|string $fgColour
* @return array
*/
function setTerminalColour($bgColour=null, $fgColour=null)
{
if(!is_null($bgColour)) {
$this->setColour($bgColour);
}
$bgColour = $this->getColour();

// convert from 8 bit colour numbers to 16 bit ones
$bgColour = $this->convertTo16bit($bgColour);

if($fgColour === null) {
$fgColour = $this->getFgColour($bgColour);
} else {
}

$bgColour = implode(',', $bgColour);
$fgColour = implode(',', $fgColour);

system("osascript -e 'tell application "Terminal"
set targetWindow to window 1
set background color of targetWindow to {" . $bgColour . "}
set cursor color of targetWindow to {" . $fgColour . "}
set normal text color of targetWindow to {" . $fgColour . "}
set bold text color of targetWindow to {" . $fgColour . "}
end tell' ");
}
}

As you can see, there’s a variety of helper methods that I’ve not show here. setColour() is the where we map from the types of input that the user will provide to an array. Other that that, it’s fairly self-explanatory.

Change colour from the command line

Now we need a script that uses our class. termcolours.php, that I can execute from the command line to change any given Terminal window to a new background colour.

termcolour.php is stored in /usr/local/bin and has execute permissions set using chmod a+x termcolour.php from the command line:


#!/usr/bin/php
<?php
include dirname(__FILE__) . '/TerminalColour.php';

process($argc, $argv);
exit;

function process($argc, $argv)
{
if($argc == 1) {
echo <<<EOT
TerminalColour: Set the background colour of a Terminal.app window
USAGE:
1. termcolour.php {r} {g} {b}
({r}, {g}, {b} are between 0 and 255)
2. termcolour.php {hexvalue}
({hexvalue} assumed to be from 000 to fff or 00000 to ffffff)

EOT;
exit;
}

$tc = new TerminalColour();
if($argc == 4) {
// called with three arguments - treat as rgb values (0-255)
array_shift($argv); // remove name of script
$tc->setTerminalColour($argv);
}

if($argc == 2) {
// called with one argument - either a lookup or a hex value
$tc->setTerminalColour($argv[1]);
}
}

Again, not complicated. we check number of arguments to the script and if there are none, we display a help message. If there are exactly 1 or 3, then we call TerminalColour::setTerminalColour() appropriately.

Hooking into SSH

Lastly we hook into ssh and change the colour based on the server name.

To do this, I’ve used a simple shell script and modified termcolours.php to add some additional colour look up entries.

/usr/local/bin/sshcolours.sh:
/usr/local/bin/termcolour.php $@
/usr/bin/ssh $@
/usr/local/bin/termcolour.php white

termcolour.php

//...

$tc = new TerminalColour();

// add colours for servers
$colourLookup = $tc->getLookupColours();
$serverColours = array(
'server1' => $colourLookup['darkblue'],
'server2' => $colourLookup['red'],
'server3' => 'C4DFC3',
);
$tc->addToLookupColours($serverColours);

if($argc == 4) {
//...

(not a large change!)

finally, we add an alias to ~/.bash_profile:

alias s=sshcolours.sh

That’s it! I can now type:

	s server1

and Terminal’s background colour turns blue and I’m ssh’d into server 1.

Sometimes I just type termcolour.php darkred to remind myself that this terminal window is doing something long-running and not to accidentally close it…

This is a zip file of the relevant files.

2 thoughts on “Changing OS X Terminal colours when ssh'ing into a server

  1. This seems a bit OTT.

    In my .profile (under Linux) I have a function getcolours with a case statement that sets up bg, fg and ms for each machine I want to be able to ssh into.

    Then, on my home terminal in .profile I have:

    for host in $hosts
    do
    getcolours
    eval "function $host {
    ssh -A -Y -T -f $host /usr/bin/xterm -sb -sl 1000 -rightbar -ms $ms -fg $fg -bg $bg -ls -u8
    }"
    done

    Now I can simply type xyz to get an xterm back from a host called xyz.may.be, with the right background and foreground colours.

    I can't see why this wouldn't work on a mac.

Comments are closed.