http:// / code / titles.shtml

Screen Titles

Ever since high school, I've been interested in using VT-100 and ANSI escape sequences to make normal text look better on a display. I don't know why, but it's always been something I wanted to know more about, and then use more often.

If you're not familiar with what "escape sequences" are...

The first part of the page is like a history lesson- it explains what terminal control sequences are and where they came from. If you already know this stuff or you don't care, feel free to skip it.

Remember that the first computers were huge machines, the size of a refrigerator, and people used separate "terminals" to interact with them. A terminal was basically a keyboard and a display, with a serial port on the back. The serial port connected back to the computer, the computer sent characters over the serial port to have them displayed on the terminal, and the terminal sent characters over the serial port when the user pressed keys on the keyboard.

The very first terminals were actually more along the lines of typewriters- the characters coming from the computer were printed on paper. Later terminals used video displays which were capable of doing more than a typewriter could- they could show a wider range of characters, and some could do things like show different character sets, different sizes, and different colors. The high-end terminals could be used as full graphic displays, and in some cases had a mouse attached to them. (This is different from X/Window displays, which were actually computers in their own right.)

When the computer wanted the terminal to do something special- to move the cursor, draw characters in "reverse video" (i.e. light up the background and leave the character itself dark), or use a different color, it would send a string of control codes to the terminal. These control codes are called "escape sequences" because the first byte of each sequence was a control code called "ESC", or "escape" (ASCII value 27 decimal, 1B hex, 033 octal, 00011011 binary.) When the terminal saw this character, it knew that the next few bytes would be a command having to do with how characters were drawn, rather than characters needing to be sent to the screen.

For example, the sequence "ESC[H" (the ESC character, a left bracket, and a capital H, in that order) told the terminal to move the cursor to the top left corner of the display. The sequence "ESC[1m" (the ESC character, a left bracket, the number 1, and a lowercase m) told the terminal that any "normal" (i.e. non-control) characters which followed should be drawn using bold characters, like the <B> tag in HTML.

All terminals with video displays had some kind of control sequences to do things like this. However, since computers and terminals made by DEC (Digital Electronics Corporation) were more widely used in college and academic settings than anything else, the people who were writing software were either using DEC equipment, or had used it in school and knew how it worked, so it ended up being the most widely used and known type of terminal on the market. Other companies who made terminals, made sure that they worked with DEC's control sequences, so that they could be easily used with DEC computers.

And because the DEC terminals were so widely used, ANSI, the American National Standards Organization, adopted most of DEC's control sequences as a standard which other companies were encouraged to use in their own products. As a result, these old DEC terminal control sequences are also known as ANSI sequences.

Why do we care about the control codes used by these old terminals anymore, when our computers now have graphic displays built into them? Most of us have seen a "command line" at one time or another- it may have been a "DOS prompt" with commands like "CD" and "DIR" and "TYPE", or a *nix command line with commands like "cd" and "ls" and "cat"... these command line interfaces almost always have support for the same control sequences that the old DEC terminals used. In some cases it had to be added to the system (using an "ANSI.SYS" driver, for example) but in most cases it's already there. The Linux console, for example, has support for these sequences built into it.

Because these control sequences are so widely used, they can be used by things like shell scripts, if they wish to use different colors or other "special effects" on the screen. That's what this web page is about.

Control Sequences

I have a set of scripts that I use whenever I set up a new server for myself or my clients... most times when I build a machine I'm always installing the same exact programs and scripts over and over again, which means I'm typing the same commands over and over again- putting those commands into a set of scripts has saved me a lot of time over the years... what used to be a four-hour setup job takes about an hour and a half now.

Part of what these scripts do is downloading, compiling, and installing software. And what I find myself doing is starting a script and letting it run, then when I come back to it, either I have to hit the "up arrow" key to see which script I just finished in order to tell what's next, or something will be going on and text will be flying by and I can't tell what's happening.

What does this have to do with ANSI escape sequences, you ask? Along with changing the text colors and moving the cursor around, you can also set a "scrolling zone" of certain lines on the screen, and if enough text is sent to the screen that the screen needs to scroll up, only the lines within the "scrolling zone" will scroll up, and any lines above or below the scrolling zone will not move- which means that by putting a message on the top line and setting the "scrolling zone" to start on line 2, that top line will not be overwritten when text scrolls up.

This allows me to put a "title" at the top of the screen, and by sending the right control codes, the title can be changed to reflect what the script is currently doing.

The relevant control codes are:

Codes Description
ESC 7 Saves the current "state", specifically the cursor position and the active visual attributes. It does NOT save the scrolling region.
ESC 8 Restores the the cursor position and active visual attributes to whatever was saved by the last "ESC7" sequence.
ESC [ r ; c H
Move the cursor to the indicated row and column on the screen. The top left corner is "1;1". If the numbers are omitted, the cursor will be moved to the top left corner of the screen. Specifying a number which is off of the screen will move the cursor to that edge of the screen.
ESC [ n K Clear text within the line. If n is 0 or missing, it clears from the cursor to the end of the line. If n is 1, it clears from the cursor to the beginning of the line. If n is 2, it clears the entire line. Note that it DOES NOT move the cursor at all.
ESC [ n ; n m Set the visual characteristics of the following characters. The command uses one or more numbers, from the following list:
0 Normal. 30 Black text. 40 Black background.
1 Bold. 31 Red text. 41 Red background.
32 Green text. 42 Green background.
33 Brown text. 43 Brown background.
4 Underlined.  34 Blue text. 44 Blue background.
5 Blinking. 35 Purple text. 45 Purple background.
36 Cyan text. 46 Cyan background.
7 Reverse. 37 White text. 47 White background.
The attributes will be added to whatever attributes may currently be in effect. If you need to ensure that no existing attributes will interfere with the ones you are setting, you should start your list of attributes with an explicit "0". For example, this sequence:
will set the text color to bold white with a red background.
ESC [ a ; b r
ESC [ a ; r
Set the scrolling region. a is the first line, and b is the last line of the scrolling region. If only the first number is specified, the bottom of the screen will be the last line in the scrolling region. The lines are numbered with line 1 at the top of the screen.

With these codes, you can set a "title" line at the top of the screen using a sequence like this:

ESC7ESC[HESC[0;1;37;41mESC[KThis is the message.ESC[2;rESC8

What it actually does:

Save the cursor position and visual attributes.
Move the cursor to the top left corner of the screen.
Set the text to bright white on a red background.
Clear to the end of the line.
This is the message.
The message for the title line.
Set the scrolling region from line 2 to the end of the screen.
Restore the cursor position and visual attributes.


Because the scripting involved is so simple, I'm just going to put the text of the scripts on the web page instead of having actual downloadable files.

The first one is a Perl script which I call "title-red". It looks like this (each "\x1B" is the "ESC" character.)

#!/usr/bin/perl -w my $msg = ( shift || "" ) ; print $msg ? "\x1B7\x1B[H\x1B[0;1;37;41m\x1B[0K$msg\x1B[2;r\x1B8" : "\x1B7\x1B[H\x1B[0m\x1B[0K\x1B[1;r\x1B8" ;

You could call this from a script or from a command line like this:

$ title-red "This is the title."

If you call it without any title text, it erases any text from the top line and sets the scrolling region back to the entire screen. I have similar scripts called "title-green", "title-yellow", "title-blue", and so forth, which have the same code but use different numbers instead of "1;37;41".

A better option, in terms of performance, is to write the appropriate functions into your scripts. If your "/bin/sh" is really bash, you can include functions like this at the top of your scripts. (For bash, "\e" is the "ESC" character, and "echo" is a built-in command, rather than the "/bin/echo" command.)

title_red() { echo -en "\e7\e[H\e[0;1;37;41m\e[K${1:-}\e[2;r\e8" ; } title_green() { echo -en "\e7\e[H\e[0;1;37;42m\e[K${1:-}\e[2;r\e8" ; } title_yellow() { echo -en "\e7\e[H\e[0;1;37;43m\e[K${1:-}\e[2;r\e8" ; } title_blue() { echo -en "\e7\e[H\e[0;1;37;44m\e[K${1:-}\e[2;r\e8" ; } title_purple() { echo -en "\e7\e[H\e[0;1;37;45m\e[K${1:-}\e[2;r\e8" ; } title_cyan() { echo -en "\e7\e[H\e[0;1;37;46m\e[K${1:-}\e[2;r\e8" ; } title_white() { echo -en "\e7\e[H\e[0;30;47m\e[K${1:-}\e[2;r\e8" ; } title_clear() { echo -en "\e7\e[H\e[K\e[1;r\e8" ; } title_reset() { echo -en "\e7\e[1;r\e8" ; }

The title_clear() function clears the top line and resets the scrolling region to the entire screen. The title_reset() function just resets the scrolling region but leaves any message there. This can be useful to leave a "Finished" messages at the top of the screen when the script is finished.

Then, later in your script, you can call these functions to set the "screen title" at appropriate points in your script. For example, one of my system setup scripts installs ezmlm, a mailing list engine for qmail, along with ezmlm-idx, a third-party add-on which adds a lot of useful features to the original ezmlm program. This is roughly what my script looks like:

# install ezmlm with ezmlm-idx patches

title_red() { echo -en "\e7\e[H\e[0;1;37;41m\e[K${1:-}\e[2;r\e8" ; }
title_reset() { echo -en "\e7\e[1;r\e8" ; }




title_red "Downloading ezmlm"
cd /usr/local/src
wget $EURL || exit 1

title_red "Downloading ezmlm-idx"
cd /usr/local/src
wget $IURL || exit 1

title_red "Expanding ezmlm"
tar xvzf ezmlm-$EVER.tar.gz || exit 1

title_red "Expanding ezmlm-idx"
tar xvzf ezmlm-idx-$IVER.tar.gz || exit 1

title_red "Moving ezmlm-idx files into the ezmlm directory
mv ezmlm-idx-$IVER/* ezmlm-$EVER/
rmdir ezmlm-idx-$IVER
mv ezmlm-$EVER ezmlm-$EVER-idx-$IVER

title_red "Applying patch"
cd ezmlm-$EVER-idx-$IVER
patch < idx.patch 2>&1 | tee output.1.patch || exit 1

title_red 'Running "make clean"'
make clean 2>&1 | tee output.2.make-clean || exit 1

title_red 'Running "make"'
make 2>&1 | tee output.3.make || exit 1

title_red 'Running "make man"'
make man 2>&1 | tee output.4.make-man || exit 1

title_red 'Running "make setup"'
make setup 2>&1 | tee output.5.make-setup || exit 1

title_red 'Finished.' title_reset