Saturday, June 20, 2009

Mac OS X: Execute Shell Commands via Icon-Clicks



My main development machine is a custom PowerBook running Ubuntu natively. I use it when I'm sitting on the couch, my office comfy chair, the futon, floor, etc. Every once in a while, though, I want to work at a desk from my 24" iMac. Just to mix it up a little. However, that box is my gaming and web-browsing machine: it runs Mac OS X and that's the way I want to keep it. So, if I'm going to do work on the iMac, I need to ssh into the machines that have the environments set up for development.

In the course of an average day of writing code, I'll connect to anywhere from 1 to 5 remote machines open up 5-10 ssh sessions in a terminal to each machine. If I'm at the iMac, this get's tedious. Today, it got tedious enough for me to do somthing about it. Here's what I want: to click on a Terminal icon and have an ssh connection automatically established to the box I need to work on. This it pretty easy on Linux and Windows, but I had no idea how to accomplish this on a Mac until tonight.

I thought I'd share my solution; others may like it... but I'm betting there are some pretty cool ways of doing this that didn't occur to me -- so feel free to share yours!


Profile Hack

From previous messing about with the open command, I knew I could open Terminal.app from the terminal:
open -n "/Applications/Utilities/Terminal.app"
This got me part way there... if only I could dynamically execute a command upon login... so, yeah, I did something nasty:
vi ~/.bash_profile
And then:
if [ ! -z "$REMOTE_CONNECTION" ]; then
ssh $REMOTE_CONNECTION
REMOTE_CONNECTION=""
fi

.command Files


I was stumped at that point, until some googling revealed a nifty trick I didn't know about:
  • Create a new file in your favorite editor, using the .command extension
  • Add the commands you want executed
  • Save it and chmod 755
  • Double-click it and enjoy
So here's what I added to rhosgobel.command:
REMOTE_CONNECTION=rhosgobel \
open -n "/Applications/Utilities/Terminal.app"

The Obligatory Icon Tweak


I then used the standard "Get Info" trick of icon copying: "Get Info" for Terminal.app, copy icon, "Get Info" for all my .command files, paste icon.


Usage


Now, I just click my "Shells" menu, choose the destination, and start working on that machine. A new window or new tab opened with that instance of Terminal.app will give me a new session to that server, without having to manually ssh into it -- this is even more convenient than having an icon to double-click!

One bit of ugly I haven't figured out how to remove: when I open a shell to a remote server, there's another shell opened at the same time with a [Process completed] message.


9 comments:

Anonymous said...

Your'e thinking too much. It's not actually that hard. Make a .command file that contains "ssh hostname". Make it executable.

Alternatively, you can make a new "setting" from within terminal preferences which runs whatever command you want. See Shell -> Startup -> Run command. If you doubleclick that ".term" file, it'll run the command. With that method, you can customize the bgcolor (and other attributes) of each terminal.

Duncan McGreggor said...

fuhm,

Thanks for the tips!

jehiah said...

You could also easily use JellyfiSSH which was essentially written for just that purpose; a way to easily store/access remote servers.

(and it will save you one sub menu from the dock)

it also has an easy interface to set different colors for different hosts, and to manage port forwarding, X11 forwarding, ...

Joe Kueser said...

Fantastic tips. Thanks! This is going to make my work life a lot easier. I have about 8 machines I have to SSH into on a daily basis.

A couple of tweaks to what fuhm said...

One, you'll get a message saying that the required extension is ".terminal" (in Leopard). I suspect ".term" works just fine, but I guess I'll let my Mac be happy and just use .terminal (or no extension at all and let it figure it out)

Before creating your first .terminal file, though, go to Shell -> Use Settings as Default. I didn't do this, and it wanted to use the "test.terminal" file I created every time I opened up Terminal. So I removed the changes I had made for the test.terminal, selected Shell -> Use Settings as Default, and now both my default stuff, and my test.terminal work in perfect harmony.

Second, I did all the tweaks, including setting the run command, in Terminal -> Preferences. Probably obvious, but just in case...

Finally, I found it very useful to check a couple of boxes in Preferences -> Settings -> Window. By checking "Settings name" (and naming my .terminal file according to the machine I'm ssh-ing into) I can see which machine it is based on the titile of that terminal window. Second, by checking "Command key" I can see what key I can press to switch to that terminal.

Only thin that would make this all better is figuring out how to open that terminal in a new tab instead of a new window...

Very exciting stuff. Thanks again!

Duncan McGreggor said...

jehiah,

Thanks for the tip! The only problem I have with jellyfiSSH is that it doesn't have a behaviour I want when logged into a remote machine: creating a new terminal or tab should provide a new connection to whatever server I am already connected to.

Sadly, if I connect to a remote server with jellyfiSSH and hit "Command-T", I get a new tab with an ssh session to localhost.

The solution I outlined does provide this behaviour. I'm going to try out some of fuhm's and Joe's tips and see if that also gives me what I need.

Anonymous said...

Best osx solution 4 me:
I use iTerm. In it you go to manage bookmarks, set the command to be the 'ssh me@work.com' stuff and associate a ^cmd key with it. Then with one keystroke inside iTerm, you have a new tab with your connection.

I am embarrassed to say that after years of OSX use I finally discovered Quicksilver for application switching. Even if you want to use iTerm it can get you into your solution with a couple of keystrokes.

with a couple of keystrokes I can be into any terminal on any machine without ever having to do that mousey-clicky-thingy.

Duncan McGreggor said...

astro,

I was trying to remember which launcher app I'd used in the past that might have supported something like this -- thanks! I'd only used Quicksilver as a launcher, really, and not taken advantage of any other features it might have had when it first came out. I wasn't as big a fan as several of my developers friends/mac users were (but that's probably because I was hardly using it).

I've just installed it and will see how its latest incarnation suits my needs...

Duncan McGreggor said...

astro,

I've checked out the ssh plugin for quicksilver, and it was okay... but I think I'd rather use quicksilver to run my terminal scripts. Still not sure if quicksilver is my thing, though... which is odd, really, since on Ubuntu I use a tiled window manager now (thanks to comments from readers!) and you'd think I'd be a good match for something like quicksilver.

As far as iTerm goes, I used to be a big fan and used it a bunch. Then it started getting really unstable on my machines and I eventually had to stop using it (random crashes, high memory usage, etc.). That being said, I just downloaded the latest (2008) and it seems to have added some nifty features. I guess the bookmarks stuff has been there for a while, but I never really used it. I have, however, used the "send to all terminals" feature a LOT (sysadmin work).

I thought I remembered an iTerm feature where when you had a tab with a connection to a server, opening another tab automatically connected you to that same server. I might have mis-remembered. though.

Anyway, the scripts that I've provided *do* have that feature (by "virtue" of the ENV variable they set), and so far, no other solution has provided this. Ah... hang on a tick... Nope, couldn't get it to work by using an ENV var in the bookmark command field (though I didn't try very hard).

Unknown said...

I'm using .command files all the time.
In fact I've them in every finder window on the toolbar.

The problem is that all of uses the same icon.

Anyone knows how to change the icon of a single .command ? so it would be easier to identify each ?