Sunday, April 24, 2011

Hack and / - Status Messages in Screen 'Linux Journal'

Mar 31, 2011  By Kyle Rankin

If you live in screen, learn how to make its status bar notify you like a pop-up window on a desktop.
If you have used the command line for any length of time, someone probably has introduced you to a program named screen. If you aren't familiar with it, screen allows you to manage multiple console sessions within the same program, so instead of dealing with tabs or multiple terminal windows, you can shift between your console sessions with a few key-presses. In addition to this, screen allows you to detach from these console sessions completely while they are still running and then reattach to them later. One use for this could be to start a process that might take some time near the end of the day at work within a screen session, detach from the session, then reattach later on that evening at home to make sure it completed.
I use screen along with Irssi on a server I leave running, so I can stay logged in to IRC at all times and just attach to that screen session from any machine I happen to be using. I also keep other console sessions in screen set up for mutt and SSH instances into various servers, so I can access everything from the same session. To be honest, I spend a majority of time in front of a computer within screen sessions.
Because I devote so much of my focus to a screen window, I've found it handy to take advantage of the status line within screen to notify me of anything that might need my attention. The status line often is off by default; however, once enabled, it takes up a row at the bottom of your console. You can configure it to list all sorts of information, from things as basic as the current date and time to as complicated as the output of any shell program you can imagine.
Configuring the status line in screen quickly can become quite complicated. There is a robust syntax of string escapes that allows you to control right and left justification and coloration of all the items in the status line. Special string escapes also allow you to specify the current time, the hostname and system load. Describing all these options is much like describing printf syntax to someone for the first time. Instead of going into all of that here, I refer you to the section of the screen man page titled STRING ESCAPES. To get there, type man screen, and once you are in the man page, type /^STRING ESCAPES, and press Enter.
For this column, I show how to enable the status line in screen and tweak it so it shows you some basic system information. Finally, I explain how to add custom script output. If you decide you want to have fancy colorized status lines, I'm sure you'll have fun experimenting with all of the options in the man page.
Enable the Status Line
Each user's individual screen settings are configured in ~/.screenrc, so to enable a basic status line, you use the hardstatus configuration option. To create a status line that says “hello world”, add the following lines to your ~/.screenrc:
hardstatus alwayslastline
hardstatus string 'hello world'

Now when you start screen, you should see “hello world” along the bottom of your window in reverse video (that is, your foreground and background colors will be reversed). Some people like that, but if you want to have white text instead, change the hardstatus string to:
hardstatus string '%{= w}hello world'

The next time you load your screen session, the text will be white. If you want, you also can change the .screenrc from within the screen session itself and reload it. Once you have saved any changes to your .screenrc, just press Ctrl-a : (that's Ctrl-a followed by the : key), then type source ~/.screenrc, and press Enter.
Since the status line works now, let's make it display more useful information, like the current date and time, and system load. Change your hardstatus string to:
hardstatus string '%{= w}%Y-%m-%d %c | %l'

This looks a bit complicated, but let's break it down. The %{= w} part of the screen sets the foreground to white. I can represent the year, month and day with %Y%m and%d, respectively, and in this case, I added a hyphen (-) in between each value so it was easier to read. Then, I added a space and %c, which is expanded into the current time. Finally, I added a | symbol with some spaces for padding and %l, which expands out into the current load.
Custom Status Scripts
As you can see in my example, screen provides a few string escapes for some common output you might want in the status line. It also allows you to define custom commands it can run and display the output on the status line instead. All you have to do is define a command in your .screenrc via the backtick option, and then reference that command in the hardstatus string. For instance, here's a simple Perl script I wrote that parses the output of fetchmail -c (which checks an IMAP account of mine for new messages). If any of my defined folders have new messages, it outputs them separated by spaces. Name the following script /usr/local/bin/new_mail_check.pl:
#!/usr/bin/perl
pen FETCHMAIL, "/usr/bin/fetchmail -t 10 -c 2>/dev/null |"
o ↪or die "Can't run fetchmail: $! \n"; while(){
$m+=$1; $s+=$2; $f=$3; # you might have to change this
if(/^(\d+) messages \((\d+) seen.*?folder (.*?)\)/){ regex depending on # how your IMAP server displays subfolders $f =~ s/INBOX\.//; } if($1 > $2){
=>$fs{$b} } keys %fs){
$fs{$f} = $1 - $2; } } close FETCHMAIL; $t = $m - $s; if($t > 0){ foreach $folder (sort { $fs{$a} < push @folders, "$folder:$fs{$folder}"; } }
print join " ", @folders;

Make sure the script is executable, then change your ~/.screenrc to the following:
backtick 101 60 60 /usr/local/bin/new_mail_check.pl
hardstatus alwayslastline
Y-%m-%d %c | %l | %101`'
hardstatus string '%{= w} %

The first line defines a backtick command that will be referred to as 101. The two 60s that follow define the life span and auto-refresh times for the command in seconds. The lifespan is defined as the number of seconds the output is considered valid before the command will be run again if the string escape is encountered. The auto-refresh value defines when to refresh the display of the hardstatus string. I usually define both values to be the same for my backtick commands. In this case, I check for new mail every 60 seconds. The final argument in the command is the full path to the command you want to run. If you need to specify any arguments, you can put them after the command. Also notice that I added %101` to the end of my hardstatus string. The %` string escape will put the specified backtick output into the status. In this case, %101` will put the output of the backtick command I define as 101. If I wanted to add another command, I'd add another backtick line to my .screenrc and define it as 102.
Figure 1. A Sample of My Decked-Out Screen Status
So, where do you go from here? Well, besides using all the string escapes to colorize your status lines, you really are limited only by your shell scripting ability. For instance, there's a program for Irssi called fnotify you can use to log everyone who highlights your handle in Irssi into a file. I wrote a simple script to pull the last line from that file, parse it, and display the date and handle of the last person who talked to me on IRC to my status bar. You also could write scripts to show you information from Twitter, headlines from your favorite sites, Nagios alert summaries or even random output from the fortune command. If you are like me though, you'll spend the bulk of your time tweaking all the colors and left and right padding, so your status looks just right.
Kyle Rankin is a Systems Architect in the San Francisco Bay Area and the author of a number of books, including The Official Ubuntu Server BookKnoppix Hacks andUbuntu Hacks. He is currently the president of the North Bay Linux Users' Group.