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!)

Jul 17, 2012 @ 16:59:18
When inside of a screen session you can type ctl-a c to spawn another shell, or “window”. Instead of detaching from the screen session with ctl-a d, you can open a new screen window (ctl-a c). ctl-a will take you to the next window. ctl-a ” will list the open windows and let you choose which one to switch to. ctl-a [integer] will jump to that window index.
You can also add these lines to your .screenrc file to start up your screen session the way you like:
screen 0 sh
screen 1 postgres
screen 2 redis-server
screen 3 sh -c “cd ~/Code/Rails/project/;bundle exec rails s”
Then you can type screen once, and all of those process will start. You will have a normal shell to work with on window 0. To checkout what rails is doing ctl-a 3. Back to what you were working on ctl-a 0. When you are done ctl-a ctl-\ or ctl-: quit
This will kill all process running in all windows in the current screen session.
When you detach a screen session with ctl-a ctl-d, you can quit terminal, open a new terminal and use screen -r to reattach to it. This has implications for using screen on a remote machine via ssh.