Tuesday, May 22, 2012

Fun with gnu screen

In my day job, I spend a fair amount of time working on numerous tasks on the command-line in Linux and OSX.  Way back in my college days, I used a program called gnu screen (aka 'screen') but recently I've "refound" it.  I have a new appreciation for screen and now use it every day.

What is screen?

Screen let's you have multiple shell sessions running simultaneously in the same terminal window.  Here's some of the features that I personally find appealing:
  • With a little muscle memory, you can switch rapidly between the sessions.
  • It has the ability to split up your terminal window into multiple "window-splits" so you can see two or more shells sessions at the same time.  The splits are even resizable.
  • You can 'detach' and 'reattach' to a screen session, allowing you to sign-out, leave and come back later, all the while keeping your terminal sessions active and running.
  • It's configurable and scriptable.
  • You can copy and paste between sessions with 'vi' like keystrokes.

How do you get screen?

Well, if you're running ubuntu like me, it's pretty darn easy.  You're one command away from having it:

steve@ubuntu64 ~ $ sudo apt-get install screen

Pretty simple.

Getting started

Once you have screen installed, simply run it.

steve@ubuntu64 ~ $ screen

It will bring you to a welcome screen (I'll show you how to disable the welcome screen later).


At the bottom of the welcome screen, it will say

[Press Space or Return to end.]

Go ahead and do that.  You'll be returned to a bash prompt.  It's important to note that screen hasn't terminated, but rather it's spawned another shell prompt within itself and you're sitting at that new prompt. You can now begin using screen via keyboard command sequences.  To prove it, press Ctrl-a and then press " (double quote).  You should get a screen that looks like this:

This is the terminal session list.  If you have more than one terminal session running, you'd seem them all listed here.  Let's create another terminal session.  Press Ctrl-a and then press c.  This should take you back to a bash prompt.  Your now in a new bash prompt.  See see the updated list, press Ctrl-a and " again.

Now there's two bash sessions.  You can select the one you'd like to see by using your arrow keys (or vi cursor movement keys) to highlight the one you want and then press enter/return.

When you want to quit out, simply exit out of all your bash prompts.  Once the last bash session ends, screen will automatically terminate, leaving where you were when you initially started it.

My most used key sequences

As you've probably realized by now, screen uses Ctrl-a plus a key to drive it's functionality.  Here's a list of key sequences that I use most often.

Ctrl-a Ctrl-a - Toggles between two sessions.  It's kind of like the "last" button on your TV remote.

Ctrl-a c - Creates a new terminal session.

Ctrl-a A - Let's you set the title of a terminal session.  The title is what appears in the session list.

Ctrl-a " - Lists the terminal sessions.  You can then use arrow keys or vi keys to select which session you wan to go to.

Ctrl-a d - Detach screen so you can log off and come back later.  Later when you sign back on, just type screen -r to reattach to your running screen session.

Ctrl-a : - Bring up screen's colon prompt (similar to vi).  From the colon prompt you can issue commands directly to screen.  (You'll probably use it most resizing window splits).

Ctrl-a [ - Start copy mode (for copy/paste).

Ctrl-a ] - Paste what you copied from copy mode.

Ctrl-a S - Split the screen horizontally.

Ctrl-a | (pipe) - Split the screen vertically.

Ctrl-a {tab} - Move focus from window split to window split

Ctrl-a X - Close the current window split.

Split example

Here a quick example of doing a couple window splits.  First, start screen and a few terminal sessions:

steve@ubuntu64 ~ $ screen
{return}
Ctrl-a c
Ctrl-a c
Ctrl-a "

Your terminal window should look like this:

Now press Ctrl-a S to split the screen.  You should now have an upper split and a lower split.  Press {return} now to select terminal session 2 in the upper split.  In that terminal session run the top command.

Now press Ctrl-a {tab}.  This will move the cursor down to the bottom split.  Then press Ctrl-a " to bring up the session list.

Select session 0 and then issue the following command in the lower split: watch ls.

Next, let's split the lower window vertically.  Press Ctrl-a | (pipe), Ctrl-a {tab}, Ctrl-a ".  Select session 1.

As you can see, you can keep splitting, sub-splitting, etc.  Remember, Ctrl-a {tab} moves the cursor to the next window split.  That's how you move around.

When you're done, you can use Ctrl-a X to close the window splits.  This does not quit/kill the process running in that split.  The process stays in the session list until you exit it normally.

Scripting

Screen reads and processes the ~/.screenrc file at startup.  Here's mine:

vbell off
startup_message off
defscrollback 1000
bindkey -k k1 colon
bindkey -k k2 screen
bindkey -k F2 windowlist -b
hardstatus off
caption always '%{Yb}[%=%t%=]'
altscreen on
shell -${SHELL}

You can go through the screen man page for what each line does.  You can customize screen however you'd like.

There are two features that combined make startup processing especially interesting:
  1. You can use the -c command line argument to give screen an alternate rc file to process on startup.
  2. Using commands, you can do anything in the rc file that you could do interactively.
Using this notion, I create different screen rc files for different contexts.  For example, when I'm working at a certain client, I would like to have screen set up a certain way, with specific terminal sessions setup.  I create a bash aliases for each client.

In my ~/.bash_aliases file I have:

alias clientX='screen -c ~/screen_profiles/clientX'
alias clientY='screen -c ~/screen_profiles/clientY'

My ~/screen_profiles/clientX file looks like this:

altscreen on
vbell off
attrcolor b ".I"
termcapinfo xterm 'Co#256:AB=\E[48;5;%dm:AF=\E[38;5;%dm'
defbce "on"
defscrollback 1500
bindkey -k k1 colon
bindkey -k k2 screen
bindkey -k F2 windowlist -b
screen -t "Home" bash
screen -t "Build" ssh my_username@build_server
screen -t "Dev2" ssh my_username@dev_server
screen -t "WebLogic" my_username@weblogic_server
screen -t "Todo/Notes" vi ~/notes/todo.markdown
hardstatus off
caption always '%{Yb}[%=%t%=]'
select 0
split -v
resize +20
focus
select 5
focus

This rc file does the following:
  • Does some normal setup that I do anyway (key bindings, colors, etc.)
  • Creates a terminal session titled, "Home" and runs bash in it.
  • Creates a terminal session titled, "Build" and ssh's me into the build server.
  • Creates a terminal session titled, "Dev2" and ssh's me into the dev 2 server.
  • Creates a terminal session titled, "WebLogic" and ssh's me into the weblogic server.
  • Creates a terminal session titled, "Todo/Notes" and edits my ~/notes/todo.markdown file using vi in it.
  • Splits the window vertically, resizing the left window to be 20 columns bigger.
  • Selects the "Home" session for the left window.
  • Selects the "Todo/Notes" session for the right window.
  • Puts the cursor focus on the left window.
So when I come into clientX's office for the day, I simply type clientX at the bash prompt and within a second, I have screen all set up with my splits and automatically logged into all the servers I commonly use.  Pretty cool.