Wednesday, November 2, 2011

Gnu Screen - The *nix Swiss Army Knife

GNU Screen - The Unix/Linux Swiss Army Knife

1. Introduction

Screen is most commonly described as a terminal multiplexer. It allows you to manage and interact with multiple processes (usually shells) using a single virtual terminal (eg: xterm window) or console. Each screen window provides an emulated VT100 terminal. In addition to its multiplexing abilities, screen has a miriade of useful features. Some of these include: split window support, scroll back history, copy-and-paste mechanism, status bar, serial terminal support, and session sharing. Screen is an extremely feature rich program. In this article, I will attempt to show, by-example, how to take advantage of the features that I have found the most useful.

2. Installation

Screen has been around a long time, so it should be available from your Linux distribution's package manager. One of the following commands should install screen on your system:

sudo apt-get install screen
su -c "yum install screen"
If you want to install screen from source code, you can download it here.

3. Basic usage

Once you have screen installed, open up a terminal window and type

Chances are you will be greeted with a welcome screen which can be dismissed by hitting Enter. You now have your default shell prompt running inside a screen session! You may have noticed that nothing looks any different. By default screen, stays out of your way so you barely know it's there. To reassure yourself that you actually are running screen, type the following key combination:
ctrl-a ?

This will list all screen commands. Note that you must prefix each of the commands listed with the command character ctrl-a. All key bindings can be remapped. This includes the command character (ctrl-a), which Emacs users in particular may wish to remap. I will discuss customization in a later section.

This long list of commands can be intimidating, but rest assured, I only use a small subset in my daily use of screen. Here are the most important commands to get you started:

ctrl-a c        Creates an new terminal window
ctrl-a w        Lists all windows
ctrl-a n        Move focus to the next window
ctrl-a p        Move focus to the previous window
ctrl-a k        Kill the current widow
ctrl-a /        Kill all windows and quit
ctrl-a a        Send a literal ctrl-a (beginning of line in emacs) 
ctrl-a A        Rename the current window
ctrl-a ctrl-a   Switch to the previously selected window
With just these commands you can take advantage of Screen's multiplexing abilities.

Warning: if you install screen from your distribution's package manager, it is possible that the package has installed a non-standard global configuration file overwriting some of the default behaviors in screen. Check the file /etc/screenrc. I know that Fedora 13 has a pretty extensive /etc/screenrc and some default key bindings have been altered.

4. Detaching

Screen allows you to "detach" from a session and then subsequently "reattach" later with all of your windows and processes preserved. Detaching basically puts your session into the background and reattaching brings it back to the foreground. This may not seem that exciting at first glance but consider the following use case:

You are logged into a university Linux box via ssh hammering away on an important programming assignment. You have been debugging a pesky function and have not saved your work in hours. Suddenly, your laptop loses wireless connectivity due to that crummy wireless router you've been meaning to replace. Unfortunately, you were not using screen so your editor is terminated when you lose your ssh connection and your hard work is lost!

This could have been prevented! Screen could have saved your work, had you logged in to the university box via ssh and then started a screen session on the remote machine.

laptop> ssh remote
remote> screen
remote> vim hw.c
In the event that you lose your ssh connection to the remote machine, your screen session will simply detach. After you reestablish an ssh connection, you can resume your screen session with something like the following:
laptop> ssh remote
remote> screen -ls
    There are screens on:
        4364.pts-0.localhost       (Detached)
remote> screen -r 4364
Commands explained:
screen -ls   Lists all active (Attached or Detached) screen sessions
screen -r id  Attach to the screen session represented by id
This can also be useful if you want to run a process on a remote machine that could take a long time. For example, let's say you have an old server on which you would like to run an overnight backup script. You could do something like the following:
laptop> ssh server
server> screen ./backup_script
ctrl-a d   (This will detach you from the screen session.)
You could then logout of the remote server and shutdown your laptop for the night. The next morning, you could ssh into the server, reattach to your screen session and check the progress of your backup.
laptop> ssh server
server> screen -RR
Commands explained:
screen -RR  This attaches to the first screen session it can find and if none are found, creates a new one.

You can attach and detach from a session as many times as you want.

If you have screen available, there is no reason not to use it when working remotely via ssh. It can save you.

Summary of commands:
ctrl-a d Detach from the current screen session.
screen -ls List all active screen sessions.
screen -r Reattach to a specific screen session.
screen -RR Reattach to the first active session or create a new one.

5. Copy-Paste and scroll back

Screen allows you to scroll back through our terminal history and copy and paste text to any window in the current screen session. Type the following command to enter copy mode:

ctrl-a [
You can use the arrow keys to navigate as well as the PgUp and PgDn keys for faster scrolling. Once you have your cursor at the beginning of some text you would like to copy, press the space bar to set a mark. Now use the arrow keys to select the text you want and set another mark by hitting the space bar again. Your selected text has been copied into a buffer. You can paste the buffer back into any window in the current screen session by switching to that window and typing the following command:
ctrl-a ]

This can be very convenient and efficient, especially if you are stuck on a console without a mouse!

The number of lines that screen caches for scroll back is configurable and will be discussed in the Customization section.

6. Customization and scripting

Screen is extremely configurable. The complexities of its configuration are one of the biggest stumbling blocks for new users. The easiest way to get past this is to steal someone else's configuration and mold it into your own. Screen is configured using the local configuration file ~/.screenrc and the global configuration file /etc/screenrc. My master ~/.screenrc is provided below. Feel free to steal it! Note that I run screen inside a 256color xterm so your mileage may vary if you use something else.

In addition to this master .screenrc file, I like to have small .screenrc files that start up programs in nicely labeled tabs. Here is an example of my email .screenrc:

You can run screen with a non-standard configuration file like this:
screen -c ~/.screenrc-mail

It's also common for users to have a tab for IRC chat (eg: weechat, irssi), system monitoring (eg: top, htop, tail -f /var/log/messages), text-based web browser (eg: elinks, w3m, lynx), extra terminals, etc. The possibilities are endless!

One use case that has really helped my workflow is creating .screenrc files for programming projects.

Let's assume that you have a beautifully organized home directory and that a project is located in ~/projects/school/cs101/hw1/. In addition, it's a client/server application so you have a directory for the client and server respectively. Every time you want to work on this project, you have to open a terminal, start screen cd ~/projects/school/cs101/hw1/client, open another window, cd ~/projects/school/cs101/hw1/server, open another window for man pages, etc. So much typing!

We could write a dedicated .screenrc for the project. Here is one that follows the example:

Now all we have to type is:

screen -c ~/.screenrc-myproj

We don't even have to startup our editor. Additionally, if you were working on this project at home on your desktop and you have to run to class, you can detach your session and take your laptop to class. Then you can ssh into your desktop from your laptop, reattach to your running session, and instantly have your entire development environment at your finger tips.

Here is another version that uses a horizontal split screen for the client and server code:

This gives us a nice split screen view! (I will cover the commands for navigating split screens in a later section).

Screen is completely scriptable. Anything that you can do with commands, can be done via .screenrc. This makes screen extremely powerful.

7. Notifications with backticks

One line in my .screenrc file that might seem odd is the following:
# New mail notification
backtick 101 30 15 $HOME/bin/
Screen's backtick facility allows you to add notifications to your hardstatus line. In the line above, "101" is basically an identifier that represents the output of the script $HOME/bin/ The numbers 30 and 15 represent how often (in seconds) the script is run and how often the value in the hardstatus is refreshed respectively. Wherever the identifier 101 appears in the hardstatus line, it will be replaced by a string containing my mailboxes that have new mail and how many new messages each contains. I will describe how my email scripts work in a later article but you can use this to display the output of any script in your hardstatus line.

8. Split screens

Earlier I showed you how to create two windows split horizontally using a custom .screenrc file. Here are the commands to interact with split windows during a live screen session:
ctrl-a S  Split the current region into two (horizontally)
ctrl-a tab  Switches to the next region 
ctrl-a X  Kill the current region

Vertical splits in screen: screen does not yet officially support virtically split regions. There is a patch, however, that enables vertical splitting. Debian/Ubuntu usually include this patch in their packages but Redhat/Centos/Fedora do not. If you must have this feature and it is not available in your package manager, the patch can be found here. The patch is already included in the development version of screen and will eventually be included in a release.

9. Screen as a serial terminal (eg: minicom, kermit)

Anyone who has done embedded development, server administration, or telecommunications work has probably needed to interact with a device via a serial terminal at some point. A couple of the most popular serial communications programs are minicom and kermit. If you are familiar with these tools, you are in for a treat. Screen can also act as a serial terminal! Not only that but it is so much faster and easier to configure than kermit or minicom and you don't have to remember another set of key bindings. Using screen to connect to the serial port /dev/ttyUSB0 with speed 9600 is as easy as the following:
screen /dev/ttyUSB0 9600
Note: This may need to be run as root depending on how the permissions are setup for /dev/ttyUSB0.

Some useful commands for working with screen as a serial terminal are:

ctrl-a C  Clear the screen
ctrl-a ctrl-b Send a break
You can also open a serial connection in a new window from an existing screen session by issuing the following command:
ctrl-a :  
This puts you in command mode (similar to vim). Then type:
screen /dev/ttyUSB0 9600
You should then be greeted by a new window running your serial connection.

This is one of my favorite features of screen and one I didn't find out about until I had been using screen for years!

10. Nested screen sessions (screen within a screen)

At this point, I would hope that you are thoroughly convinced that screen is the most awesome program ever. You will probably run screen with every terminal on your local machine and when you ssh into other machines you will probably want to run screen there too. If you do this, you will find yourself in a screen within a screen. As cool as this sounds, it's probably better to just use an xterm on your local machine and start your screen session on the remote machine.

If you find yourself in a screen within a screen, your outermost screen (the one on your local machine in this example) will behave normally. You will find that the outermost screen will catch all of your command characters so you cannot get commands through to the inner screen session. The key here is something I mentioned previously:

ctrl-a a This sends a literal ctrl-a (as if you pressed ctrl-a in xterm)
All you have to do to issue commands to the inner screen session is replace every instance of ctrl-a with ctrl-a a.
ctrl-a a c        Create a new window
ctrl-a a k        Kills a window
ctrl-a a ctrl-a a Switch to the previously selected window
You can go as many levels deep as you want adding more ctrl-a prefixes to send commands to more deeply nested screens. I rarely do this intentionally, but it's nice to know how.

11. Screen session sharing

Have you ever wanted to really prove to one your friends just how fast and efficient your vim skills are? Have you ever had to debug a server and wanted a more experienced friend to share your terminal for guidance? If so, screen has yet another feature for you. With screen you can allow another user to connect to your session and interact with it simultaneously. In order to make this work, you are going to have to setuid root your screen binary. This is a potential security risk and I recommend that you only do it temporarily. I have not seen a way to do this without setuid but if there is one I'd like to know about it. Anyway, here are the steps:

Step 1: Setup the binary

sudo chmod +s /usr/bin/screen
sudo chmod 755 /usr/bin/screen
Step 2: Start screen with a named session (This just makes things convenient)
screen -S vim-skills
Step 3: Have your friend ssh to your machine
friend_host> ssh emacsuser@your_host
Step 4: Allow emacsuser to connect to your running screen session
ctrl-a :
multiuser on
ctrl-a :
acladd emacsuser
Step 5: Have your friend (who is now on logged into your machine) connect to your screen session
emacsusers@localhost> screen -x vim-skills
You should now be sharing a screen session. Your friend can spam your vim buffers with "I love emacs" to his hearts content as you hammer the d key.

12. Cheat sheet

ctrl-a c       Creates an new terminal window.
ctrl-a w       Lists all windows.
ctrl-a n       Move focus to the next window.
ctrl-a p       Move focus to the previous window.
ctrl-a k       Kill the current widow.
ctrl-a /       Kill all windows and quit.
ctrl-a a       Send a literal ctrl-a (beginning of line in emacs). 
ctrl-a A       Rename the current window.
ctrl-a ctrl-a  Switch to the previously selected window.
ctrl-a d       Detach from the current screen session.
ctrl-a [       Enter copy mode (scroll back mode).
ctrl-a ]       Paste copy buffer.
ctrl-a S       Split the current region into two (horizontally)
ctrl-a tab     Switches to the next region 
ctrl-a X       Kill the current region
ctrl-a C       Clears the screen
ctrl-a ctrl-b  Send a break
ctrl-a :       Command mode

screen -ls  Lists all active (Attached or Detached) screen sessions.
screen -r id  Attach to the screen session represented by id.
screen -RR  Attach to the first screen session it can find. If none, create a new one.
screen -c file Run screen with the given configuration file.
screen -S name Give your screen session a name.
screen -x name Connection to a session with name, name.
See the screen man page for a full listing of commands and features. If you have a favorite feature, put it in the comments!