I've been using GNU screen for at least a couple years, but about 3 months ago, I changed my usage of it in a pretty major way, and I'd like to share my configs.

I'm not going to explain every feature in screen; others have already done it very well:

Making Screen Multi-Window Friendly

Like (I think) most people who use screen, I don't dig not being able to tell when I'm in a screen session. I also find it helpful to have named windows, and to have to names be easily accessible; the following line from my screenrc adds a helpful caption line:

caption always "%H %= %-w%L>%{= BW}%n*%t%{-}%52<%+w %L="

Which looks like so:

A terminal showing a screen session with mock "tabs"

As you can see, this adds "tabs" at the bottom (although the screen term for them is 'windows'). Very soon after adding this, I had conventions for which windows were used for what - for a long time, I used 0 for htop, 1 for a general-purpose shell, 2 for music, 3 for emacs, and so on.

Why Use Multiple Sessions?

There are a couple problems with this. The first is that screen makes it pretty difficult to access windows above #9 - usually, you'd have to do prefix+space until you get to the window you want. Practically speaking, it meant that I hardly ever used more than 10 windows.

A second problem - exacerbated by the first - is that I would often have 5 or more windows dedicated to long-running processes - emacs, htop, an mpd client, a development server, and IRC. This left relatively little "working" room. I would run a build here, a download there, and all of a sudden I was out of available shells.

The next step I took was to separate the long-running process into a separate screen session. I would have one "processes" session and one "shells" session; screen -S allows you to name a session ("screen -S processes") which allows for easy reattaching ("screen -x processes") without having to deal with PIDs.

However, once I was running 2 screen sessions, why would I stop there? After all, if one of the processes somehow made screen crash (emacs would do this every so often), I'd lose the other processes too. And screen is extremely lightweight by modern standards; running 10 or 12 is not a problem for anything made in the last few years.

Using multiple sessions introduces a problem, however: how do you tell what session you're in?

Configs

Now, I want you to have fair warning: what I'm showing here is not technically correct. I'm going to show you some stuff from my .bashrc, which is not necessarily run when you start a screen session. For example, screen -S emacs emacs -nw would only run emacs inside of the screen session - so this wouldn't take effect.

Furthermore, every time you open a new shell, the bashrc will be run again. As long as you don't care about efficiency (and who does?) then that just means we have to be careful to make sure it's idempotent.

And a final warning: I really, really don't like writing shell. In fact, the reason it's taken me so long to write about this subject is that I'm more than a little embarrassed at the state of my bash knowledge. So all I can say about this code is that it "works for me" - not that it's correct, and certainly not that it's good.

So first, a utility function to determine if I'm in a screen session:

  1. _inside_screen()
  2. {
  3. # I hate bash.
  4. if [ "$STY" = "" ]; then
  5. echo "false"
  6. else
  7. echo "true"
  8. fi
  9. }

I can then modify the caption line that I posted above so that it uses the $STY environment variable instead of the hostname.

  1. if [ `_inside_screen` = "true" ]; then
  2. # If I'm inside screen, set the caption to show STY so I know
  3. # which screen.
  4. screen -X caption always "$STY %= %-w%L>%{= BW}%n*%t%{-}%52<%+w %L="
  5. export HISTFILE=~/.bash_history.d/`_screen_name`.$WINDOW
  6. fi

Screen sets $STY to something like "12723.pts-3" by default; using -S changes the last part of the value - for example, "12723.emacs".

Per-Window History

One thing that will start annoying you before long is the globally shared history: next time you start up a project screen session, it's history will be filled with commands from an arbitrary shell - the one that exited last and wrote out ~/.bash_history last.

Instead, the above snippet sets HISTFILE to be inside a ~/.bash_history.d/ directory (which you'll need to create). Not only does this keep your global history from getting jumbled up, but it gives you very stateful shells - when you restart a named screen session after a reboot, each window will have its pre-reboot history available.

Using Sessions In A Workflow

After making the above changes, I started using one screen session per long running process, plus one session per project/context. for example, at home I have the following:

A terminal showing a listing of named screen sessions

And that's about typical; I run about the same number of sessions at work, somewhat fewer on my laptop.

This makes my day-to-day workflow very nice - when starting work on a project, I'll "screen -x ", and it'll open up to a shell in the trunk checkout of the project that I opened some weeks earlier. The commands I ran last are still visible - or, if not, I can use screen's scrollback buffer to look at thim - and I can immediately Control-R and pick up right where I left off.

If you'd like to try it out, I'd recommend checking out my .screenrc, plus whatever other ones you can find to make your life easier. If there's one problem with screen, it's that the manpage is a rather intimidating wall of text - and it doesn't help that theres four different sets of commands to learn (the command-line options, the config file/command format, the default keybindings, and the caption/hardstatus format codes).