The Art of Zen and the Terminal

Subtitle: use screen, and cut way back on your tabs

Look at the following picture, and tell me why it sucks.

Actually, since this is a blog post, how about I tell you why it sucks instead?  I’ve got 4 other terminals open aside from the one I’m actually working in, each one showing the output from some process that I may need to reference from time to time (database, webserver, etc).  This is perfectly functional, but it makes me unhappy.  It clutters my view and therefore my mind, and I don’t like being distracted when I’m trying to work.

Enter the screen command.  Screen is a little *nix utility that lets you run processes in the foreground (so you can see the output easily) without having to have a seperate tab open for each one.  Actually, screen is WAY more than that, but that’s what we’re going to use it for today.  To demonstrate how you can make this work, lets try starting a database.  In a different screen.  At it’s simplest, you can open a new “screen” just by typing “screen” at the command prompt:

$> screen

This will give you a little intro message which you can press [space] to get past, and then you’re at a new prompt (probably something like “bash-3.2$”).  go ahead and start your database:

bash-3.2$> postgres

Now you’ll start seeing the normal output as your DB starts up. You might think you’ve gained exactly nothing, as just like usual, you’re unable to do much else with this prompt as long as the DB is running. However, you’ll think differently when you do the following:

ctrl-a  d

In screen, ctrl-a allows you to issue several directives, one of which is to “detach” your terminal from the current screen (hence the “d” key above). Your screen should now look something like this:

$> screen
[detached]
$>

OK, now you have no access to the output again, right? I mean, how is this better than just running the database in the background with “&” and redirecting the output to a file you go check when you have to? Honestly, it might not be if you’re JUST looking at output; anything you might want to interact with, though, will benefit from the fact that you can also switch back into that screen anytime with this:

$> screen -r

Now that you’ve seen what this can do with a single screen, let’s start several at once:

$> screen -dmS pg postgres
$> screen -dmS redis redis-server
$> screen -dmS rails sh -c "cd ~/Code/Rails/project/; bundle exec rails s"
$>

Each of these lines is starting a new screen, totally on its own. The “d” and “m” flags together create a screen that’s immediately detached, the “S” flag lets you give it a name (like “pg”, “redis”, or “rails”) and then the rest is the command you want that screen to execute. Thus all these processes are running now, and you only have the single tab open. Can’t remember what screens you had running? Try this:

$> screen -ls
There are screens on:
	17567.pg	(Detached)
	17569.redis	(Detached)
	17574.rails	(Detached)
3 Sockets in /var/folders/sA/sA33EZkQFbuxJMC5mHZbuE+++TI/-Tmp-/.screen.

Look at that! Those are the screens we have open, and each of them has a name! Want to check in on the output of your rails server?

$> screen -r rails

Remember to use “ctrl-a d” to get back to your main terminal again after. Want to see if redis is getting anything set into it?

$> screen -r redis

You can still flip back and forth easily without cluttering your terminal with tab headers. Now, who’s ready for extra credit? Taking those commands we ran above, let’s put them into a bash script called “startup” in the “script” directory of a rails project:

#!/bin/bash
screen -dmS pg postgres
screen -dmS redis redis-server
screen -dmS rails sh -c "cd ~/Code/Rails/project/;bundle exec rails s"

now whenever you want to run your development environment, you can just do the following:

$> ./script/startup

and blam! Everything is up and ready to go, and you can go check on any of them by swapping screens. Now, shutting down is a little more tricky, so I’m going to just give you the script and it’s YOUR turn to figure out how it works and why it’s written that way (and if you find a better way to do it, leave a comment! I’d love something a little nicer myself). Here’s the equivalent ‘shutdown’ file:

#!/bin/bash
ps | grep '[0-9] postgres' | awk '{print $1}' | xargs kill
ps | grep '[0-9] redis-server' | awk '{print $1}' | xargs kill
ps | grep '[0-9] sh -c cd' | awk '{print $1}' | xargs kill

Now meditate on the state of your terminal. (Gong!)