How to show SSH host name on the iTerm’s background

Posted by Dmytro Shteflyuk on under Mac OS X

iTerm How many ssh session do you open usually? In Scribd we have about 50 machines, and most of the time I have to connect to several of them to do my work. But there is a big problem — it’s hard to distinguish among different tabs in iTerm. Of course, you can see the host where you connected to in the tab title, but the title is really small, low contrast, etc. So I had a dream since I’ve started using Mac — to get current host written with large letters on the background.

iTerm has a great support of AppleScript. Looking through the commands list I’ve found a really useful one: background image path. The last thing to figure out is how to create an image with the current host name, and I decided to use ImageMagick. So, let’s do it!

First, you need to install ImageMagick. You can use binary distribution, but I’d prefer the MacPorts version:

1
port install ImageMagick

Let’s create a test image:

1
2
3
convert -size "570x342" xc:black -gravity "NorthEast" -fill "#662020" \
        -family "Georgia" -style "Normal" -pointsize "60" -antialias \
        -draw "text 20,10 'kpumuk.info'" "/tmp/iTermBG.png"

Here is the result and it looks pretty good!

Image with hostname

Ok, now the most interesting part. I’ve created a bash script in ~/bin/ssh, which sets the background before calling ssh and clears it on exit. I suppose you have this folder specified before /usr/bin in your .bash_profile:

1
export PATH=$HOME/bin:/opt/local/bin:$PATH

Here is the script (the latest version could be found in a GitHub repository here):

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
#!/bin/bash

# SSH with host name and IP address in background (only in iTerm.app)

# First, check to see if we have the correct terminal!
if [ "$(tty)" == 'not a tty' ] || [ "$TERM_PROGRAM" != "iTerm.app" ] ; then
  /usr/bin/ssh "$@"
  exit $?
fi

function __calculate_iterm_window_dimensions {
  local size=( $(osascript -e "tell application "iTerm"
    get bounds of window 1
  end tell"
| tr ',' ' ') )

  local x1=${size[0]} y1=${size[1]} x2=${size[2]} y2=${size[3]}
  # 15px - scrollbar width
  local w=$(( $x2 - $x1 - 15 ))
  # 44px - titlebar + tabs height
  local h=$(( $y2 - $y1 - 44))
  echo "${w}x${h}"
}

# Console dimensions
DIMENSIONS=$(__calculate_iterm_window_dimensions)

BG_COLOR="#000000"       # Background color
FG_COLOR="#662020"       # Foreground color
GRAVITY="NorthEast"      # Text gravity (NorthWest, North, NorthEast,
                         # West, Center, East, SouthWest, South, SouthEast)
OFFSET1="20,10"          # Text offset (host name)
OFFSET2="20,80"          # Text offset (ip address)
FONT_SIZE="60"           # Font size in points
FONT_STYLE="Normal"      # Font style (Any, Italic, Normal, Oblique)
# Font path
FONT="$HOME/.bash/resources/SimpleLife.ttf"

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

output=`dscacheutil -q host -a name $HOSTNAME`
RESOLVED_HOSTNAME=`echo -e "$output"|grep '^name:'|awk '{print $2}'`
RESOLVED_IP=`echo -e "$output"|grep '^ip_address:'|awk '{print $2}'`

function set_bg {
  local tty=$(tty)
  osascript -e "
    tell application "
iTerm"
      repeat with theTerminal in terminals
        tell theTerminal
          try
            tell session id "
$tty"
              set background image path to "
$1"
            end tell
          on error errmesg number errn
          end try
        end tell
      end repeat
    end tell"

}

on_exit () {
  if [ ! -f /tmp/iTermBG.empty.png ]; then
    convert -size "$DIMENSIONS" xc:"$BG_COLOR" "/tmp/iTermBG.empty.png"
  fi
  set_bg "/tmp/iTermBG.empty.png"
  rm "/tmp/iTermBG.$$.png"
}
trap on_exit EXIT

convert \
  -size "$DIMENSIONS" xc:"$BG_COLOR" -gravity "$GRAVITY" -fill "$FG_COLOR" \
  -font "$FONT" -style "$FONT_STYLE" -pointsize "$FONT_SIZE" -antialias \
  -draw "text $OFFSET1 '${RESOLVED_HOSTNAME:-$HOSTNAME}'" \
  -pointsize 30 -draw "text $OFFSET2 '${RESOLVED_IP:-}'" \
  "/tmp/iTermBG.$$.png"
set_bg "/tmp/iTermBG.$$.png"

/usr/bin/ssh "$@"

The script is big, but very simple. In lines 6-9 script detects the current terminal application, and if it is not iTerm — skips the background generation. Also it checks if the SSH connection was requested from an interactive command line or from an another script (e.g., from git). If you want to see what host git tries to connect to — remove the tty check. Function on lines 11-22 calculates the iTerm window size, so generated background will not be stretched. If you have disabled scrollbars — remove - 15 on line 18. Configuration options determining how host name will be printed on your background are on lines 27-36. Lines 38-42 normalize host name and resolve IP address. Function on lines 44-59 changes background of the iTerm tab where ssh command was invoked from using AppleScript. It’s tricky a little, but still easy to understand. Lines 61-68 trap script exit. They handle special case when you kill ssh session, and get background image for non-ssh console. Lines 70-76 generate background image using ImageMagick.

Let’s see it in action:

So now I can stop shaking with fear when doing some destructive things in console — I know which host exactly I’m trying to kill. I hope you will find this post useful.

Changelog

05/01/2009: Updated on_exit function to fix bug with scrolling after ssh session being closed.

05/03/2009: Added some variables to customize how host name will look.

06/23/2010: Better console size detection, added normalization of host name, and IP address below the hostname, iTerm detection (to prevent errors in Terminal.app).

9 Responses to this entry

Subscribe to comments with RSS

said on May 1st, 2009 at 11:42 · Permalink

It’s interesting feature. But I think it’s not very useful.

dgs
said on May 2nd, 2009 at 05:05 · Permalink

Very cool, that would be so useful in large data centers!!!

j2
said on May 6th, 2009 at 21:48 · Permalink

This will work better with arguments passed to ssh:

1
HOSTNAME=`echo $@ | sed 's/.* \(.*\)$/\1/' | sed "s/.*@//"`

e.g. on OSX -Y forwards X11 connections easily, but using your sed expressions the command ssh -Y myhost will result in -Y being the image shown in the background.

Also, you still need to be careful that you are on the host that you logged onto originally from OSX. if you chain your ssh’s your background image will be incorrect.

said on July 2nd, 2009 at 15:34 · Permalink

Hi,

Thanks a lot for this, that solved problems I had for ages connecting to too many servers….

just a little problem, the background image disapear when I enter full screen (CMD-Enter)

cheers

julien

Doug Vasquez
said on September 17th, 2009 at 18:11 · Permalink

Great tip, thanks for sharing!

I did discover an error when attempting to run in snow leopard (v10.6.1):

1
2
3
Error loading /Library/ScriptingAdditions/Adobe Unit Types.osax/Contents/MacOS/Adobe Unit Types:  dlopen(/Library/ScriptingAdditions/Adobe Unit Types.osax/Contents/MacOS/Adobe Unit Types, 262): no suitable image found.  Did find:
/Library/ScriptingAdditions/Adobe Unit Types.osax/Contents/MacOS/Adobe Unit Types: no matching architecture in universal wrapper
osascript: OpenScripting.framework - scripting addition "/Library/ScriptingAdditions/Adobe Unit Types.osax" declares no loadable handlers.

After a quick google search, I ran into a post (http://forums.adobe.com/thread/486208) that suggested prefixing the osascript command with the appropriate supported architecture:

1
arch -i386 osascript ...

So if anyone runs into this issue, just change the following line:

1
osascript -e "tell application "iTerm"

with this:

1
arch -i386 osascript -e "tell application "iTerm"
Andrew McFague
said on October 1st, 2009 at 15:23 · Permalink

I loved this, but the problem is, I use a fullscreen monitor specifically for SSH at work, but I only have my regular laptop screen at home. So, of course, the background would be extremely distorted.

So I came up with the following; this should net you the approximate resolution by converting the rows/columns to a resolution. I simply used the ratio of the columns/rows to the resolution on my laptop:

1
2
3
4
# Generate dimension based on screensize
H=$((1440/178*`stty size | cut -d ' ' -f2`))
V=$((900/47*`stty size | cut -d ' ' -f1`))
DIMENSIONS=$H"x"$V

Its not foolproof, but its very dynamic and works great for me! :)

Andrew

Andrew McFague
said on October 6th, 2009 at 15:45 · Permalink

A quick improvement I had to implement when dealing with non-terminal windows (i.e., bash scripts):

1
2
3
4
5
6
7
# First, check to see if we have the correct terminal!
[ "$( tty )" == 'not a tty' ] && /usr/bin/ssh "$@" && exit

# Generate dimension based on screensize
H=$((1440 / 178 * `stty size | cut -d ' ' -f2` ))
V=$((900 / 47 * `stty size | cut -d ' ' -f2` ))
DIMENSIONS=$H"x"$V    # Console dimensions

This uses the the tty variable to detect whether or not its a terminal session, so it won’t try and grab the screen size from stdin-less sessions. Note, this depends on the tty variable being set which, from my basic testing, works flawlessly on bash-3.2.

Andrew

said on October 6th, 2009 at 15:48 · Permalink

That’s sweet, thank you! Will test on my machine and update the post. Good work!

Andrew McFague
said on October 6th, 2009 at 19:24 · Permalink

Wait! I realized a mistake; ssh doesn’t always exit with a 0 status, even though it may be a normal exit. To make it a little clearer, the following worked:

1
2
3
4
5
# First, check to see if we have the correct terminal!
if [ "$( tty )" == 'not a tty' ] ; then
    /usr/bin/ssh "$@"
    exit
fi

Comments are closed

Comments for this entry are closed for a while. If you have anything to say – use a contact form. Thank you for your patience.