Bash Prompt HOWTO

$Revision: 0.93 $, $Date: 2003/11/06 02:12:02 $

Giles Orr

Copyright © 1998, 1999, 2000, 2001, 2003 Giles Orr


Creating and controlling terminal and xterm prompts is discussed, including
incorporating standard escape sequences to give username, current working
directory, time, etc. Further suggestions are made on how to modify xterm
title bars, use external functions to provide prompt information, and how to
use ANSI colours. 

Permission is granted to copy, distribute and/or modify this document under
the terms of the GNU Free Documentation License, Version 1.1 or any later
version published by the Free Software Foundation; with no Invariant
Sections, with no Front-Cover Texts, and with no Back-Cover Texts. A copy of
the license is included in the section entitled "GNU Free Documentation
License". 

-----------------------------------------------------------------------------
Table of Contents
1. Introduction and Administrivia
    1.1. Introduction
    1.2. Revision History
    1.3. Requirements
    1.4. How To Use This Document
    1.5. Document Versions, Comments and Suggestions
    1.6. Problems
    1.7. Credits/Bibliography
    1.8. Disclaimer
   
   
2. Bash and Bash Prompts
    2.1. What is Bash?
    2.2. What Can Tweaking Your Bash Prompt Do For You?
    2.3. Why Bother?
    2.4. The First Step
    2.5. Bash Prompt Escape Sequences
    2.6. Setting the PS? Strings Permanently
   
   
3. Bash Programming and Shell Scripts
    3.1. Variables
    3.2. Quotes and Special Characters
    3.3. Command Substitution
    3.4. Non-Printing Characters in Prompts
    3.5. Sourcing a File
    3.6. Functions, Aliases, and the Environment
   
   
4. External Commands
    4.1. PROMPT_COMMAND
    4.2. External Commands in the Prompt
    4.3. What to Put in Your Prompt
   
   
5. Saving Complex Prompts
6. ANSI Escape Sequences: Colours and Cursor Movement
    6.1. Colours
    6.2. Cursor Movement
    6.3. Xterm Title Bar Manipulations
    6.4. Xterm Title Bars and Screen
    6.5. Colours and Cursor Movement With tput
   
   
7. Special Characters: Octal Escape Sequences
8. The Bash Prompt Package
    8.1. Availability
    8.2. Xterm Fonts
    8.3. Changing the Xterm Font
    8.4. Line Draw Characters without VGA Fonts
   
   
9. Loading a Different Prompt
    9.1. Loading a Different Prompt, Later
    9.2. Loading a Different Prompt, Immediately
    9.3. Loading Different Prompts in Different X Terms
   
   
10. Loading Prompt Colours Dynamically
    10.1. A "Proof of Concept" Example
   
   
11. Prompt Code Snippets
    11.1. Built-in Escape Sequences
    11.2. Date and Time
    11.3. Counting Files in the Current Directory
    11.4. Total Bytes in the Current Directory
    11.5. Checking the Current TTY
    11.6. Stopped Jobs Count
    11.7. Load
    11.8. Uptime
    11.9. Number of Processes
    11.10. Controlling the Size and Appearance of $PWD
    11.11. Laptop Power
    11.12. Having the Prompt Ignored on Cut and Paste
    11.13. New Mail
    11.14. Prompt Beeps After Long-Running Commands
   
   
12. Example Prompts
    12.1. Examples on the Web
    12.2. A "Lightweight" Prompt
    12.3. Dan's Prompt
    12.4. Elite from Bashprompt Themes
    12.5. A "Power User" Prompt
    12.6. Prompt Depending on Connection Type
    12.7. A Prompt the Width of Your Term
    12.8. The Floating Clock Prompt
    12.9. The Elegant Useless Clock Prompt
   
   
A. GNU Free Documentation License
    0. PREAMBLE
    1. APPLICABILITY AND DEFINITIONS
    2. VERBATIM COPYING
    3. COPYING IN QUANTITY
    4. MODIFICATIONS
    5. COMBINING DOCUMENTS
    6. COLLECTIONS OF DOCUMENTS
    7. AGGREGATION WITH INDEPENDENT WORKS
    8. TRANSLATION
    9. TERMINATION
    10. FUTURE REVISIONS OF THIS LICENSE
    How to use this License for your documents
   
   

-----------------------------------------------------------------------------
Chapter 1. Introduction and Administrivia

1.1. Introduction

I've been maintaining this document for nearly six years (I believe the first
submitted version was January 1998). I've received a lot of e-mail, almost
all of it positive with a lot of great suggestions, and I've had a really
good time doing this. Thanks to everyone for the support, suggestions, and
translations! 

I've had several requests both from individuals and the LDP group to issue a
new version of this document, and it's long past due (two and a half years
since the last version) - for which I apologize. Converting this monster to
DocBook format was a daunting task, and then when I realized that I could now
include images, I decided I needed to include all the cool examples that
currently reside on my homepage. Adding these is a slow process, especially
since I'm improving the code as I go, so only a few are included so far. This
document will probably always feel incomplete to me ... I think however that
it's reasonably sound from a technical point of view (although I have some
mailed in fixes that aren't in here yet - if you've heard from me, they'll
get in here eventually) so I'm going to post it and hope I can get to another
version soon. 

One other revision of note: this document (as requested by the LDP) is now
under the GFDL. Enjoy. 
-----------------------------------------------------------------------------

1.2. Revision History

Revision History                                                             
Revision v0.93            2003-11-06                                         
Removal of very outdated "Translations" section.                             
Revision v0.92            2003-11-06                                         
Added section on line draw in RXVT.                                          
Revision v0.91            2002-01-31                                         
Fixed text and code to "Total Bytes" snippet.                                
Revision v0.90            2001-08-24            Revised by: go               
Added section on screen and Xterm titlebars.                                 
Revision v0.89            2001-08-20            Revised by: go               
Added clockt example, several example images added, improved laptop power    
code, minor tweaks.                                                          
Revision v0.85            2001-07-31            Revised by: go               
Major revisions, plus change from Linuxdoc to DocBook.                       
Revision v0.76            1999-12-31            Revised by: go               
Revision v0.60            1998-01-07            Revised by: go               
Initial public release?                                                      
-----------------------------------------------------------------------------

1.3. Requirements

You will need Bash. This should be easy: it's the default shell for just
about every Linux distribution I know of. The commonest version is now 2.0.x.
Version 1.14.7 was the standard for a long time, but that started to fade
around 2000. I've been using Bash 2.0.x for quite a while now. With recent
revisions of the HOWTO (later than July 2001) I've been using a lot of code
(mainly ${} substitutions) that I believe is specific to 2.x and may not work
with Bash 1.x. You can check your Bash version by typing echo $BASH_VERSION
at the prompt. On my machine, it responds with 2.05a.0(1)-release. 

Shell programming experience would be good, but isn't essential: the more you
know, the more complex the prompts you'll be able to create. I assume a basic
knowledge of shell programming and Unix utilities as I go through this
tutorial. However, my own shell programming skills are limited, so I give a
lot of examples and explanation that may appear unnecessary to an experienced
shell programmer. 
-----------------------------------------------------------------------------

1.4. How To Use This Document

I include a lot of examples and explanatory text. Different parts will be of
varying usefulness to different people. This has grown long enough that
reading it straight through would be difficult - just read the sections you
need, backtrack as necessary.
-----------------------------------------------------------------------------

1.5. Document Versions, Comments and Suggestions

This is a learning experience for me. I've come to know a fair bit about what
can be done to create interesting and useful Bash Prompts, but I need your
input to correct and improve this document. I no longer make code checks
against older versions of Bash, let me know of any incompatibilities you
find.  

The latest version of this document should always be available at [http://
www.gilesorr.com/bashprompt/] http://www.gilesorr.com/bashprompt/ (usually
only in HTML format). The latest official release should always be at [http:/
/www.tldp.org/] http://www.tldp.org/. Please check these out, and feel free
to e-mail me at <giles at dreaming dot org> with suggestions. 

I use the Linux Documentation Project HOWTOs almost exclusively in the HTML
format, so when I convert this from DocBook SGML (its native format), HTML is
the only format I check thoroughly. If there are problems with other formats,
I may not know about them and I'd appreciate a note about them. 

There are issues with the PDF and RTF conversions (as of December 2000),
including big problems with example code wrapping around the screen and
getting mangled. I always keep my examples less than 80 characters wide, but
the PDF version seems to wrap around 60. Please use online examples if the
code in these versions don't work for you. But they do look very pretty. 
-----------------------------------------------------------------------------

1.6. Problems

This is a list of problems I've noticed while programming prompts. Don't
start reading here, and don't let this list discourage you - these are mostly
quite minor details. Just check back if you run into anything odd. 

  * Many Bash features (such as math within $(()) among others) are compile
    time options. If you're using a binary distribution such as comes with a
    standard Linux distribution, all such features should be compiled in. But
    if you're working on someone else's system, this is worth keeping in mind
    if something you expected to work doesn't. Some notes about this in 
    Learning the Bash Shell second edition, p.260-262. 
   
  * The terminal screen manager "screen" doesn't always get along with ANSI
    colours. I'm not a screen expert, unfortunately. Versions older than
    3.7.6 may cause problems, but newer versions seem to work well in all
    cases. Old versions reduce all prompt colours to the standard foreground
    colour in X terminals. 
   
  * Xdefaults files can override colours. Look in ~/.Xdefaults for lines
    referring to XTerm*background and XTerm*foreground (or possibly XTerm*
    Background and XTerm*Foreground). 
   
  * One of the prompts mentioned in this document uses the output of "jobs" -
    as discussed at that time, "jobs" output to a pipe is broken in Bash
    2.02. 
   
  * ANSI cursor movement escape sequences aren't all implemented in all X
    terminals. That's discussed in its own section. 
   
  * Some nice looking pseudo-graphics can be created by using a VGA font
    rather than standard Linux fonts. Unfortunately, these effects look awful
    if you don't use a VGA font, and there's no way to detect within a term
    what kind of font it's using. 
   
  * Things that work under Bash 1.14.7 don't necessarily work the same under
    2.0+, or vice versa. 
   
  * I often use the code PS1="...\\$${NO_COLOUR} " at the end of my PS1
    string. The \\$ is replaced by a "$" for a normal user, and a "#" if you
    are root, and the ${NO_COLOUR} is an escape sequence that stops any
    colour modifications made by the prompt. However, I've had problems
    seeing the "#" when I'm root. I believe this is because Bash doesn't like
    two dollar signs in a row. Use PS1="...\\$ ${NO_COLOUR}" instead. I'm
    still trying to figure out how to get rid of that extra space. 
   

-----------------------------------------------------------------------------
1.7. Credits/Bibliography

In producing this document, I have borrowed heavily from the work of the
Bashprompt project, which was at [http://bash.current.nu/] http://
bash.current.nu/. This site was removed from its server as of July 2001 but
Robert Current, the admin, assured me it would reappear soon. Unfortunately,
it appears he's now (May 2003) let his domain registration lapse. The work of
that project is carried on indirectly by Bashish (http://
bashish.sourceforge.net/), with whom I've had no contact. Other sources used
include the xterm Title mini-HOWTO by Ric Lister, available at [http://
www.tldp.org/HOWTO/mini/Xterm-Title.html] http://www.tldp.org/HOWTO/mini/
Xterm-Title.html, Ansi Prompts by Keebler, available at [http://
www.ncal.verio.com/~keebler/ansi.html] http://www.ncal.verio.com/~keebler/
ansi.html (now deceased), How to make a Bash Prompt Theme by Stephen Webb,
available at [http://bash.current.nu/bash/HOWTO.html] http://bash.current.nu/
bash/HOWTO.html (also deceased), and X ANSI Fonts by Stumpy, available at
[http://home.earthlink.net/~us5zahns/enl/ansifont.html] http://
home.earthlink.net/~us5zahns/enl/ansifont.html. 

Also of immense help were several conversations and e-mails from Dan, who
used to work at Georgia College & State University, whose knowledge of Unix
far exceeded mine. He gave me several excellent suggestions, and ideas of his
have led to some interesting prompts. 

Three books that have been very useful while programming prompts are Linux in
a Nutshell by Jessica Heckman Perry (O'Reilly, 3rd ed., 2000), Learning the
Bash Shell by Cameron Newham and Bill Rosenblatt (O'Reilly, 2nd ed., 1998)
and Unix Shell Programming by Lowell Jay Arthur (Wiley, 1986. This is the
first edition, the fourth came out in 1997). 
-----------------------------------------------------------------------------

1.8. Disclaimer

This document is available for free, and, while I have done the best I can to
make it accurate and up to date, I take no responsibility for any problems
you may encounter resulting from the use of this document. 
-----------------------------------------------------------------------------

Chapter 2. Bash and Bash Prompts

2.1. What is Bash?

Descended from the Bourne Shell, Bash is a GNU product, the "Bourne Again SH
ell." It's the standard command line interface on most Linux machines. It
excels at interactivity, supporting command line editing, completion, and
recall. It also supports configurable prompts - most people realize this, but
don't know how much can be done. 
-----------------------------------------------------------------------------

2.2. What Can Tweaking Your Bash Prompt Do For You?

Most Linux systems have a default prompt in one colour (usually gray) that
tells you your user name, the name of the machine you're working on, and some
indication of your current working directory. This is all useful information,
but you can do much more with the prompt: all sorts of information can be
displayed (tty number, time, date, load, number of users, uptime ...) and the
prompt can use ANSI colours, either to make it look interesting, or to make
certain information stand out. You can also manipulate the title bar of an
Xterm to reflect some of this information. 
-----------------------------------------------------------------------------

2.3. Why Bother?

Beyond looking cool, it's often useful to keep track of system information.
One idea that I know appeals to some people is that it makes it possible to
put prompts on different machines in different colours. If you have several
Xterms open on several different machines, or if you tend to forget what
machine you're working on and delete the wrong files (or shut down the server
instead of the workstation), you'll find this a great way to remember what
machine you're on. 

For myself, I like the utility of having information about my machine and
work environment available all the time. And I like the challenge of trying
to figure out how to put the maximum amount of information into the smallest
possible space while maintaining readability. 

Perhaps the most practical aspect of colourizing your prompt is the ability
to quickly spot the prompt when you use scrollback. 
-----------------------------------------------------------------------------

2.4. The First Step

The appearance of the prompt is governed by the shell variable PS1. Command
continuations are indicated by the PS2 string, which can be modified in
exactly the same ways discussed here - since controlling it is exactly the
same, and it isn't as "interesting," I'll mostly be modifying the PS1 string.
(There are also PS3 and PS4 strings. These are never seen by the average user
- see the Bash man page if you're interested in their purpose.) To change the
way the prompt looks, you change the PS1 variable. For experimentation
purposes, you can enter the PS1 strings directly at the prompt, and see the
results immediately (this only affects your current session, and the changes
go away when you exit the current shell). If you want to make a change to the
prompt permanent, look at the section below Section 2.6. 

Before we get started, it's important to remember that the PS1 string is
stored in the environment like any other environment variable. If you modify
it at the command line, your prompt will change. Before you make any changes,
you can save your current prompt to another environment variable:
+---------------------------------------------------------------------------+
|[giles@nikola giles]$ SAVE=$PS1                                            |
|[giles@nikola giles]$                                                      |
+---------------------------------------------------------------------------+

The simplest prompt would be a single character, such as:
+---------------------------------------------------------------------------+
|[giles@nikola giles]$ PS1=$                                                |
|$ls                                                                        |
|bin   mail                                                                 |
|$                                                                          |
+---------------------------------------------------------------------------+

This demonstrates the best way to experiment with basic prompts, entering
them at the command line. Notice that the text entered by the user appears
immediately after the prompt: I prefer to use
+---------------------------------------------------------------------------+
|$PS1="$ "                                                                  |
|$ ls                                                                       |
|bin   mail                                                                 |
|$                                                                          |
+---------------------------------------------------------------------------+

which forces a space after the prompt, making it more readable. To restore
your original prompt, just call up the variable you stored:
+---------------------------------------------------------------------------+
|$ PS1=$SAVE                                                                |
|[giles@nikola giles]$                                                      |
+---------------------------------------------------------------------------+
-----------------------------------------------------------------------------

2.5. Bash Prompt Escape Sequences

There are a lot of escape sequences offered by the Bash shell for insertion
in the prompt. From the Bash 2.04 man page:
+---------------------------------------------------------------------------+
|       When  executing  interactively,  bash displays the primary          |
|       prompt PS1 when it is ready to read  a  command,  and  the          |
|       secondary  prompt PS2 when it needs more input to complete          |
|       a command.  Bash allows these prompt strings  to  be  cus­          |
|       tomized by inserting a number of backslash-escaped special          |
|       characters that are decoded as follows:                             |
|              \a     an ASCII bell character (07)                          |
|              \d     the date  in  "Weekday  Month  Date"  format          |
|                     (e.g., "Tue May 26")                                  |
|              \e     an ASCII escape character (033)                       |
|              \h     the hostname up to the first `.'                      |
|              \H     the hostname                                          |
|              \j     the  number of jobs currently managed by the          |
|                     shell                                                 |
|              \l     the basename of the shell's terminal  device          |
|                     name                                                  |
|              \n     newline                                               |
|              \r     carriage return                                       |
|              \s     the  name  of  the shell, the basename of $0          |
|                     (the portion following the final slash)               |
|              \t     the current time in 24-hour HH:MM:SS format           |
|              \T     the current time in 12-hour HH:MM:SS format           |
|              \@     the current time in 12-hour am/pm format              |
|              \u     the username of the current user                      |
|              \v     the version of bash (e.g., 2.00)                      |
|              \V     the release of bash,  version  +  patchlevel          |
|                     (e.g., 2.00.0)                                        |
|              \w     the current working directory                         |
|              \W     the  basename  of the current working direc­          |
|                     tory                                                  |
|              \!     the history number of this command                    |
|              \#     the command number of this command                    |
|              \$     if the effective UID is 0, a #, otherwise  a          |
|                     $                                                     |
|              \nnn   the  character  corresponding  to  the octal          |
|                     number nnn                                            |
|              \\     a backslash                                           |
|              \[     begin a sequence of non-printing characters,          |
|                     which could be used to embed a terminal con­          |
|                     trol sequence into the prompt                         |
|              \]     end a sequence of non-printing characters             |
+---------------------------------------------------------------------------+

For long-time users, note the new \j and \l sequences: these are new in 2.03
or 2.04.

Continuing where we left off:
+---------------------------------------------------------------------------+
|[giles@nikola giles]$ PS1="\u@\h \W> "                                     |
|giles@nikola giles> ls                                                     |
|bin   mail                                                                 |
|giles@nikola giles>                                                        |
+---------------------------------------------------------------------------+

This is similar to the default on most Linux distributions. I wanted a
slightly different appearance, so I changed this to:
+---------------------------------------------------------------------------+
|giles@nikola giles> PS1="[\t][\u@\h:\w]\$ "                                |
|[21:52:01][giles@nikola:~]$ ls                                             |
|bin   mail                                                                 |
|[21:52:15][giles@nikola:~]$                                                |
+---------------------------------------------------------------------------+
-----------------------------------------------------------------------------

2.6. Setting the PS? Strings Permanently

Various people and distributions set their PS? strings in different places.
The most common places are /etc/profile, /etc/bashrc, ~/.bash_profile, and ~
/.bashrc . Johan Kullstam (johan19 at idt dot net) writes: 

   
    the PS1 string should be set in .bashrc. this is because non-interactive
    bashes go out of their way to unset PS1. the bash man page tells how the
    presence or absence of PS1 is a good way of knowing whether one is in an
    interactive vs non-interactive (ie script) bash session.
   
    the way i realized this is that startx is a bash script. what this means
    is, startx will wipe out your prompt. when you set PS1 in .profile (or
    .bash_profile), login at console, fire up X via startx, your PS1 gets
    nuked in the process leaving you with the default prompt.
   
    one workaround is to launch xterms and rxvts with the -ls option to force
    them to read .profile. but any time a shell is called via a
    non-interactive shell-script middleman PS1 is lost. system(3) uses sh -c
    which if sh is bash will kill PS1. a better way is to place the PS1
    definition in .bashrc. this is read every time bash starts and is where
    interactive things - eg PS1 should go.
   
    therefore it should be stressed that PS1=..blah.. should be in .bashrc
    and not .profile.
   
I tried to duplicate the problem he explains, and encountered a different
one: my PROMPT_COMMAND variable (which will be introduced later) was blown
away. My knowledge in this area is somewhat shaky, so I'm going to go with
what Johan says.
-----------------------------------------------------------------------------

Chapter 3. Bash Programming and Shell Scripts

3.1. Variables

I'm not going to try to explain all the details of Bash scripting in a
section of this HOWTO, just the details pertaining to prompts. If you want to
know more about shell programming and Bash in general, I highly recommend 
Learning the Bash Shell by Cameron Newham and Bill Rosenblatt (O'Reilly,
1998). Oddly, my copy of this book is quite frayed. Again, I'm going to
assume that you know a fair bit about Bash already. You can skip this section
if you're only looking for the basics, but remember it and refer back if you
proceed much farther. 

Variables in Bash are assigned much as they are in any programming language:
+---------------------------------------------------------------------------+
|testvar=5                                                                  |
|foo=zen                                                                    |
|bar="bash prompt"                                                          |
+---------------------------------------------------------------------------+

Quotes are only needed in an assignment if a space (or special character,
discussed shortly) is a part of the variable.

Variables are referenced slightly differently than they are assigned:
+---------------------------------------------------------------------------+
|> echo $testvar                                                            |
|5                                                                          |
|> echo $foo                                                                |
|zen                                                                        |
|> echo ${bar}                                                              |
|bash prompt                                                                |
|> echo $NotAssigned                                                        |
|                                                                           |
|>                                                                          |
+---------------------------------------------------------------------------+

A variable can be referred to as $bar or ${bar}. The braces are useful when
it is unclear what is being referenced: if I write $barley do I mean ${bar}
ley or ${barley}? Note also that referencing a value that hasn't been
assigned doesn't generate an error, instead returning nothing. 
-----------------------------------------------------------------------------

3.2. Quotes and Special Characters

If you wish to include a special character in a variable, you will have to
quote it differently:
+---------------------------------------------------------------------------+
|> newvar=$testvar                                                          |
|> echo $newvar                                                             |
|5                                                                          |
|> newvar="$testvar"                                                        |
|> echo $newvar                                                             |
|5                                                                          |
|> newvar='$testvar'                                                        |
|> echo $newvar                                                             |
|$testvar                                                                   |
|> newvar=\$testvar                                                         |
|> echo $newvar                                                             |
|$testvar                                                                   |
|>                                                                          |
+---------------------------------------------------------------------------+

The dollar sign isn't the only character that's special to the Bash shell,
but it's a simple example. An interesting step we can take to make use of
assigning a variable name to another variable name is to use eval to
dereference the stored variable name: 
+---------------------------------------------------------------------------+
|> echo $testvar                                                            |
|5                                                                          |
|> echo $newvar                                                             |
|$testvar                                                                   |
|> eval echo $newvar                                                        |
|5                                                                          |
|>                                                                          |
+---------------------------------------------------------------------------+

Normally, the shell does only one round of substitutions on the expression it
is evaluating: if you say echo $newvar the shell will only go so far as to
determine that $newvar is equal to the text string $testvar, it won't
evaluate what $testvar is equal to. eval forces that evaluation. 
-----------------------------------------------------------------------------

3.3. Command Substitution

In almost all cases in this document, I use the $(<command>) convention for
command substitution: that is,  
+---------------------------------------------------------------------------+
|$(date +%H%M)                                                              |
+---------------------------------------------------------------------------+

means "substitute the output from the date +%H%M command here." This works in
Bash 2.0+. In some older versions of Bash, prior to 1.14.7, you may need to
use backquotes (`date +%H%M`). Backquotes can be used in Bash 2.0+, but are
being phased out in favor of $(), which nests better. If you're using an
earlier version of Bash, you can usually substitute backquotes where you see
$(). If the command substitution is escaped (ie. \$(command) ), then use
backslashes to escape BOTH your backquotes (ie. \'command\' ).  
-----------------------------------------------------------------------------

3.4. Non-Printing Characters in Prompts

Many of the changes that can be made to Bash prompts that are discussed in
this HOWTO use non-printing characters. Changing the colour of the prompt
text, changing an Xterm title bar, and moving the cursor position all require
non-printing characters. 

If I want a very simple prompt consisting of a greater-than sign and a space:
+---------------------------------------------------------------------------+
|[giles@nikola giles]$ PS1='> '                                             |
|>                                                                          |
+---------------------------------------------------------------------------+

This is just a two character prompt. If I modify it so that it's a bright
yellow greater-than sign (colours are discussed in their own section): 
+---------------------------------------------------------------------------+
|> PS1='\033[1;33m>\033[0m '                                                |
|>                                                                          |
+---------------------------------------------------------------------------+

This works fine - until you type in a large command line. Because the prompt
still only consists of two printing characters (a greater-than sign and a
space) but the shell thinks that this prompt is eleven characters long (I
think it counts '\033' , '[1' and '[0' as one character each). You can see
this by typing a really long command line - you will find that the shell
wraps the text before it gets to the edge of the terminal, and in most cases
wraps it badly. This is because it's confused about the actual length of the
prompt. 

So use this instead: 
+---------------------------------------------------------------------------+
|> PS1='\[\033[1;33m\]>\[\033[0m\] '                                        |
+---------------------------------------------------------------------------+

This is more complex, but it works. Command lines wrap properly. What's been
done is to enclose the '\033[1;33m' that starts the yellow colour in '\[' and
'\]' which tells the shell "everything between these escaped square brackets,
including the brackets themselves, is a non-printing character." The same is
done with the '\033[0m' that ends the colour. 
-----------------------------------------------------------------------------

3.5. Sourcing a File

When a file is sourced (by typing either source filename or . filename at the
command line), the lines of code in the file are executed as if they were
printed at the command line. This is particularly useful with complex
prompts, to allow them to be stored in files and called up by sourcing the
file they are in. 

In examples, you will find that I often include #!/bin/bash at the beginning
of files including functions. This is not necessary if you are sourcing a
file, just as it isn't necessary to chmod +x a file that is going to be
sourced. I do this because it makes Vim (my editor of choice, no flames
please - you use what you like) think I'm editing a shell script and turn on
colour syntax highlighting. 
-----------------------------------------------------------------------------

3.6. Functions, Aliases, and the Environment

As mentioned earlier, PS1, PS2, PS3, PS4, and PROMPT_COMMAND are all stored
in the Bash environment. For those of us coming from a DOS background, the
idea of tossing big hunks of code into the environment is horrifying, because
that DOS environment was small, and didn't exactly grow well. There are
probably practical limits to what you can and should put in the environment,
but I don't know what they are, and we're probably talking a couple of orders
of magnitude larger than what DOS users are used to. As Dan put it: 

   
    "In my interactive shell I have 62 aliases and 25 functions. My rule of
    thumb is that if I need something solely for interactive use and can
    handily write it in bash I make it a shell function (assuming it can't be
    easily expressed as an alias). If these people are worried about memory
    they don't need to be using bash. Bash is one of the largest programs I
    run on my linux box (outside of Oracle). Run top sometime and press 'M'
    to sort by memory - see how close bash is to the top of the list. Heck,
    it's bigger than sendmail! Tell 'em to go get ash or something." 
   
I guess he was using console only the day he tried that: running X and X
apps, I have a lot of stuff larger than Bash. But the idea is the same: the
environment is something to be used, and don't worry about overfilling it. 

I risk censure by Unix gurus when I say this (for the crime of
over-simplification), but functions are basically small shell scripts that
are loaded into the environment for the purpose of efficiency. Quoting Dan
again: "Shell functions are about as efficient as they can be. It is the
approximate equivalent of sourcing a bash/bourne shell script save that no
file I/O need be done as the function is already in memory. The shell
functions are typically loaded from [.bashrc or .bash_profile] depending on
whether you want them only in the initial shell or in subshells as well.
Contrast this with running a shell script: Your shell forks, the child does
an exec, potentially the path is searched, the kernel opens the file and
examines enough bytes to determine how to run the file, in the case of a
shell script a shell must be started with the name of the script as its
argument, the shell then opens the file, reads it and executes the
statements. Compared to a shell function, everything other than executing the
statements can be considered unnecessary overhead." 

Aliases are simple to create: 
+---------------------------------------------------------------------------+
|alias d="ls --color=tty --classify"                                        |
|alias v="d --format=long"                                                  |
|alias rm="rm -i"                                                           |
+---------------------------------------------------------------------------+

Any arguments you pass to the alias are passed to the command line of the
aliased command (ls in the first two cases). Note that aliases can be nested,
and they can be used to make a normal unix command behave in a different way.
(I agree with the argument that you shouldn't use the latter kind of aliases
- if you get in the habit of relying on "rm *" to ask you if you're sure, you
may lose important files on a system that doesn't use your alias.) 

Functions are used for more complex program structures. As a general rule,
use an alias for anything that can be done in one line. Functions differ from
shell scripts in that they are loaded into the environment so that they work
more quickly. As a general rule again, you would want to keep functions
relatively small, and any shell script that gets relatively large should
remain a shell script rather than turning it into a function. Your decision
to load something as a function is also going to depend on how often you use
it. If you use a small shell script infrequently, leave it as a shell script.
If you use it often, turn it into a function. 

To modify the behaviour of ls, you could do something like the following: 
+---------------------------------------------------------------------------+
|function lf                                                                |
|{                                                                          |
|    ls --color=tty --classify $*                                           |
|    echo "$(ls -l $* | wc -l) files"                                       |
|}                                                                          |
+---------------------------------------------------------------------------+

This could readily be set as an alias, but for the sake of example, we'll
make it a function. If you type the text shown into a text file and then
source that file, the function will be in your environment, and be
immediately available at the command line without the overhead of a shell
script mentioned previously. The usefulness of this becomes more obvious if
you consider adding more functionality to the above function, such as using
an if statement to execute some special code when links are found in the
listing. 
-----------------------------------------------------------------------------

Chapter 4. External Commands

4.1. PROMPT_COMMAND

Bash provides an environment variable called PROMPT_COMMAND. The contents of
this variable are executed as a regular Bash command just before Bash
displays a prompt. 
+---------------------------------------------------------------------------+
|[21:55:01][giles@nikola:~] PS1="[\u@\h:\w]\$ "                             |
|[giles@nikola:~] PROMPT_COMMAND="date +%H%M"                               |
|2155                                                                       |
|[giles@nikola:~] d                                                         |
|bin   mail                                                                 |
|2156                                                                       |
|[giles@nikola:~]                                                           |
+---------------------------------------------------------------------------+

What happened above was that I changed PS1 to no longer include the \t escape
sequence (added in a previous section), so the time was no longer a part of
the prompt. Then I used date +%H%M to display the time in a format I like
better. But it appears on a different line than the prompt. Tidying this up
using echo -n ... as shown below works with Bash 2.0+, but appears not to
work with Bash 1.14.7: apparently the prompt is drawn in a different way, and
the following method results in overlapping text. 
+---------------------------------------------------------------------------+
|2156                                                                       |
|[giles@nikola:~] PROMPT_COMMAND="echo -n [$(date +%H%M)]"                  |
|[2156][giles@nikola:~]$                                                    |
|[2156][giles@nikola:~]$ d                                                  |
|bin   mail                                                                 |
|[2157][giles@nikola:~]$ unset PROMPT_COMMAND                               |
|[giles@nikola:~]                                                           |
+---------------------------------------------------------------------------+

echo -n ... controls the output of the date command and suppresses the
trailing newline, allowing the prompt to appear all on one line. At the end,
I used the unset command to remove the PROMPT_COMMAND environment variable. 
-----------------------------------------------------------------------------

4.2. External Commands in the Prompt

You can use the output of regular Linux commands directly in the prompt as
well. Obviously, you don't want to insert a lot of material, or it will
create a large prompt. You also want to use a fast command, because it's
going to be executed every time your prompt appears on the screen, and delays
in the appearance of your prompt while you're working can be very annoying.
(Unlike the previous example that this closely resembles, this does work with
Bash 1.14.7.)
+---------------------------------------------------------------------------+
|[21:58:33][giles@nikola:~]$ PS1="[\$(date +%H%M)][\u@\h:\w]\$ "            |
|[2159][giles@nikola:~]$ ls                                                 |
|bin   mail                                                                 |
|[2200][giles@nikola:~]$                                                    |
+---------------------------------------------------------------------------+

It's important to notice the backslash before the dollar sign of the command
substitution. Without it, the external command is executed exactly once: when
the PS1 string is read into the environment. For this prompt, that would mean
that it would display the same time no matter how long the prompt was used.
The backslash protects the contents of $() from immediate shell
interpretation, so date is called every time a prompt is generated. 

Linux comes with a lot of small utility programs like date, grep, or wc that
allow you to manipulate data. If you find yourself trying to create complex
combinations of these programs within a prompt, it may be easier to make an
alias, function, or shell script of your own, and call it from the prompt.
Escape sequences are often required in bash shell scripts to ensure that
shell variables are expanded at the correct time (as seen above with the date
command): this is raised to another level within the prompt PS1 line, and
avoiding it by creating functions is a good idea. 

An example of a small shell script used within a prompt is given below:
#!/bin/bash                                                                  
#     lsbytesum - sum the number of bytes in a directory listing             
TotalBytes=0                                                                 
for Bytes in $(ls -l | grep "^-" | awk '{ print $5 }')                       
do                                                                           
    let TotalBytes=$TotalBytes+$Bytes                                        
done                                                                         
TotalMeg=$(echo -e "scale=3 \n$TotalBytes/1048576 \nquit" | bc)              
echo -n "$TotalMeg"                                                          

I used to keep this as a function, it now lives as a shell script in my ~/bin
directory, which is on my path. Used in a prompt: 
+---------------------------------------------------------------------------+
|[2158][giles@nikola:~]$ PS1="[\u@\h:\w (\$(lsbytesum) Mb)]\$ "             |
|[giles@nikola:~ (0 Mb)]$ cd /bin                                           |
|[giles@nikola:/bin (4.498 Mb)]$                                            |
+---------------------------------------------------------------------------+
-----------------------------------------------------------------------------

4.3. What to Put in Your Prompt

You'll find I put username, machine name, time, and current directory name in
most of my prompts. With the exception of the time, these are very standard
items to find in a prompt, and time is probably the next most common
addition. But what you include is entirely a matter of personal taste. Here
is an interesting example to help give you ideas. 

Dan's prompt is minimal but very effective, particularly for the way he
works. 
+---------------------------------------------------------------------------+
|[giles@nikola:~]$ PS1="\!,\l,\$?\$ "                                       |
|1095,4,0$ non-command                                                      |
|bash: non-command: command not found                                       |
|1096,4,127$                                                                |
+---------------------------------------------------------------------------+

Dan doesn't like that having the current working directory can resize the
prompt drastically as you move through the directory tree, so he keeps track
of that in his head (or types "pwd"). He learned Unix with csh and tcsh, so
he uses his command history extensively (something many of us weaned on Bash
do not do), so the first item in the prompt is the history number. The second
item is the tty number, an item that can be useful to "screen" users. The
third item is the exit value of the last command/pipeline (note that this is
rendered useless by any command executed within the prompt - you can work
around that by capturing it to a variable and playing it back, though).
Finally, the "\$" is a dollar sign for a regular user, and switches to a hash
mark ("#") if the user is root. 
-----------------------------------------------------------------------------

Chapter 5. Saving Complex Prompts

As the prompts you use become more complex, it becomes more and more
cumbersome to type them in at the prompt, and more practical to make them
into some sort of text file. I have adopted the method used by the Bashprompt
package (discussed later in this document: Chapter 8), which is to put the
primary commands for the prompt in one file with the PS1 string in particular
defined within a function of the same name as the file itself. It's not the
only way to do it, but it works well. Take the following example: 
+---------------------------------------------------------------------------+
|#!/bin/bash                                                                |
|                                                                           |
|function tonka {                                                           |
|                                                                           |
|#   Named "Tonka" because of the colour scheme                             |
|                                                                           |
|local WHITE="\[\033[1;37m\]"                                               |
|local LIGHT_BLUE="\[\033[1;34m\]"                                          |
|local YELLOW="\[\033[1;33m\]"                                              |
|local NO_COLOUR="\[\033[0m\]"                                              |
|                                                                           |
|case $TERM in                                                              |
|    xterm*|rxvt*)                                                          |
|        TITLEBAR='\[\033]0;\u@\h:\w\007\]'                                 |
|        ;;                                                                 |
|    *)                                                                     |
|        TITLEBAR=""                                                        |
|        ;;                                                                 |
|esac                                                                       |
|                                                                           |
|PS1="$TITLEBAR\                                                            |
|$YELLOW-$LIGHT_BLUE-(\                                                     |
|$YELLOW\u$LIGHT_BLUE@$YELLOW\h\                                            |
|$LIGHT_BLUE)-(\                                                            |
|$YELLOW\$PWD\                                                              |
|$LIGHT_BLUE)-$YELLOW-\                                                     |
|\n\                                                                        |
|$YELLOW-$LIGHT_BLUE-(\                                                     |
|$YELLOW\$(date +%H%M)$LIGHT_BLUE:$YELLOW\$(date \"+%a,%d %b %y\")\         |
|$LIGHT_BLUE:$WHITE\\$ $LIGHT_BLUE)-$YELLOW-$NO_COLOUR "                    |
|                                                                           |
|PS2="$LIGHT_BLUE-$YELLOW-$YELLOW-$NO_COLOUR "                              |
|                                                                           |
|}                                                                          |
+---------------------------------------------------------------------------+

You can work with it as follows:  
+---------------------------------------------------------------------------+
|[giles@nikola:/bin (4.498 Mb)]$ cd      (1)                                |
|[giles@nikola:~ (0 Mb)]$ vim tonka      (2)                                |
|...                                     (3)                                |
|[giles@nikola:~ (0 Mb)]$ source tonka   (4)                                |
|[giles@nikola:~ (0 Mb)]$ tonka          (5)                                |
|[giles@nikola:~ (0 Mb)]$ unset tonka    (6)                                |
+---------------------------------------------------------------------------+

(1) Move to the directory where you want to save the prompt
(2) Edit the prompt file with your preferred editor
(3) Enter the prompt text given above as "tonka"
(4) Read the prompt function into the environment
(5) Execute the prompt function
(6) Optionally, unclutter your environment by unsetting the function

-----------------------------------------------------------------------------
Chapter 6. ANSI Escape Sequences: Colours and Cursor Movement

6.1. Colours

As mentioned before, non-printing escape sequences have to be enclosed in \[\
033[ and \]. For colour escape sequences, they should also be followed by a
lowercase m.

If you try out the following prompts in an xterm and find that you aren't
seeing the colours named, check out your ~/.Xdefaults file (and possibly its
bretheren) for lines like XTerm*Foreground: BlanchedAlmond. This can be
commented out by placing an exclamation mark ("!") in front of it. Of course,
this will also be dependent on what terminal emulator you're using. This is
the likeliest place that your term foreground colours would be overridden.

To include blue text in the prompt:
+---------------------------------------------------------------------------+
|PS1="\[\033[34m\][\$(date +%H%M)][\u@\h:\w]$ "                             |
+---------------------------------------------------------------------------+

The problem with this prompt is that the blue colour that starts with the 34
colour code is never switched back to the regular colour, so any text you
type after the prompt is still in the colour of the prompt. This is also a
dark shade of blue, so combining it with the bold code might help:
+---------------------------------------------------------------------------+
|PS1="\[\033[1;34m\][\$(date +%H%M)][\u@\h:\w]$\[\033[0m\] "                |
+---------------------------------------------------------------------------+

The prompt is now in light blue, and it ends by switching the colour back to
nothing (whatever foreground colour you had previously).

Here are the rest of the colour equivalences:
+---------------------------------------------------------------------------+
|Black       0;30     Dark Gray     1;30                                    |
|Blue        0;34     Light Blue    1;34                                    |
|Green       0;32     Light Green   1;32                                    |
|Cyan        0;36     Light Cyan    1;36                                    |
|Red         0;31     Light Red     1;31                                    |
|Purple      0;35     Light Purple  1;35                                    |
|Brown       0;33     Yellow        1;33                                    |
|Light Gray  0;37     White         1;37                                    |
+---------------------------------------------------------------------------+

Daniel Dui (ddui@iee.org) points out that to be strictly accurate, we must
mention that the list above is for colours at the console. In an xterm, the
code 1;31 isn't "Light Red," but "Bold Red." This is true of all the colours.

You can also set background colours by using 44 for Blue background, 41 for a
Red background, etc. There are no bold background colours. Combinations can
be used, like Light Red text on a Blue background: \[\033[44;1;31m\],
although setting the colours separately seems to work better (ie. \[\033[44m
\]\[\033[1;31m\]). Other codes available include 4: Underscore, 5: Blink, 7:
Inverse, and 8: Concealed.

Note Many people (myself included) object strongly to the "blink" attribute  
     because it's extremely distracting and irritating. Fortunately, it      
     doesn't work in any terminal emulators that I'm aware of - but it will  
     still work on the console.                                              

Note If you were wondering (as I did) "What use is a 'Concealed' attribute?!"
     - I saw it used in an example shell script (not a prompt) to allow      
     someone to type in a password without it being echoed to the screen.    
     However, this attribute doesn't seem to be honoured by many terms other 
     than "Xterm."                                                           

Based on a prompt called "elite2" in the Bashprompt package (which I have
modified to work better on a standard console, rather than with the special
xterm fonts required to view the original properly), this is a prompt I've
used a lot:
                                                                             
function elite                                                               
{                                                                            
                                                                             
local GRAY="\[\033[1;30m\]"                                                  
local LIGHT_GRAY="\[\033[0;37m\]"                                            
local CYAN="\[\033[0;36m\]"                                                  
local LIGHT_CYAN="\[\033[1;36m\]"                                            
local NO_COLOUR="\[\033[0m\]"                                                
                                                                             
case $TERM in                                                                
    xterm*|rxvt*)                                                            
        local TITLEBAR='\[\033]0;\u@\h:\w\007\]'                             
        ;;                                                                   
    *)                                                                       
        local TITLEBAR=""                                                    
        ;;                                                                   
esac                                                                         
                                                                             
local temp=$(tty)                                                            
local GRAD1=${temp:5}                                                        
PS1="$TITLEBAR\                                                              
$GRAY-$CYAN-$LIGHT_CYAN(\                                                    
$CYAN\u$GRAY@$CYAN\h\                                                        
$LIGHT_CYAN)$CYAN-$LIGHT_CYAN(\                                              
$CYAN\#$GRAY/$CYAN$GRAD1\                                                    
$LIGHT_CYAN)$CYAN-$LIGHT_CYAN(\                                              
$CYAN\$(date +%H%M)$GRAY/$CYAN\$(date +%d-%b-%y)\                            
$LIGHT_CYAN)$CYAN-$GRAY-\                                                    
$LIGHT_GRAY\n\                                                               
$GRAY-$CYAN-$LIGHT_CYAN(\                                                    
$CYAN\$$GRAY:$CYAN\w\                                                        
$LIGHT_CYAN)$CYAN-$GRAY-$LIGHT_GRAY "                                        
PS2="$LIGHT_CYAN-$CYAN-$GRAY-$NO_COLOUR "                                    
}                                                                            

I define the colours as temporary shell variables in the name of readability.
It's easier to work with. The "GRAD1" variable is a check to determine what
terminal you're on. Like the test to determine if you're working in an Xterm,
it only needs to be done once. The prompt you see look like this, except in
colour:
+---------------------------------------------------------------------------+
|--(giles@gcsu202014)-(30/pts/6)-(0816/01-Aug-01)--                         |
|--($:~/tmp)--                                                              |
+---------------------------------------------------------------------------+

To help myself remember what colours are available, I wrote a script that
output all the colours to the screen. Daniel Crisman has supplied a much
nicer version which I include below:
#!/bin/bash                                                                  
#                                                                            
#   This file echoes a bunch of color codes to the                           
#   terminal to demonstrate what's available.  Each                          
#   line is the color code of one forground color,                           
#   out of 17 (default + 16 escapes), followed by a                          
#   test use of that color on all nine background                            
#   colors (default + 8 escapes).                                            
#                                                                            
                                                                             
T='gYw'   # The test text                                                    
                                                                             
echo -e "\n                 40m     41m     42m     43m\                     
     44m     45m     46m     47m";                                           
                                                                             
for FGs in '    m' '   1m' '  30m' '1;30m' '  31m' '1;31m' '  32m' \         
           '1;32m' '  33m' '1;33m' '  34m' '1;34m' '  35m' '1;35m' \         
           '  36m' '1;36m' '  37m' '1;37m';                                  
  do FG=${FGs// /}                                                           
  echo -en " $FGs \033[$FG  $T  "                                            
  for BG in 40m 41m 42m 43m 44m 45m 46m 47m;                                 
    do echo -en "$EINS \033[$FG\033[$BG  $T  \033[0m";                       
  done                                                                       
  echo;                                                                      
done                                                                         
echo                                                                         
-----------------------------------------------------------------------------

6.2. Cursor Movement

ANSI escape sequences allow you to move the cursor around the screen at will.
This is more useful for full screen user interfaces generated by shell
scripts, but can also be used in prompts. The movement escape sequences are
as follows:
+---------------------------------------------------------------------------+
|- Position the Cursor:                                                     |
|  \033[<L>;<C>H                                                            |
|     Or                                                                    |
|  \033[<L>;<C>f                                                            |
|  puts the cursor at line L and column C.                                  |
|- Move the cursor up N lines:                                              |
|  \033[<N>A                                                                |
|- Move the cursor down N lines:                                            |
|  \033[<N>B                                                                |
|- Move the cursor forward N columns:                                       |
|  \033[<N>C                                                                |
|- Move the cursor backward N columns:                                      |
|  \033[<N>D                                                                |
|                                                                           |
|- Clear the screen, move to (0,0):                                         |
|  \033[2J                                                                  |
|- Erase to end of line:                                                    |
|  \033[K                                                                   |
|                                                                           |
|- Save cursor position:                                                    |
|  \033[s                                                                   |
|- Restore cursor position:                                                 |
|  \033[u                                                                   |
+---------------------------------------------------------------------------+

The latter two codes are NOT honoured by many terminal emulators. The only
ones that I'm aware of that do are xterm and nxterm - even though the
majority of terminal emulators are based on xterm code. As far as I can tell,
rxvt, kvt, xiterm, and Eterm do not support them. They are supported on the
console.

Try putting in the following line of code at the prompt (it's a little
clearer what it does if the prompt is several lines down the terminal when
you put this in): echo -en "\033[7A\033[1;35m BASH \033[7B\033[6D" This
should move the cursor seven lines up screen, print the word " BASH ", and
then return to where it started to produce a normal prompt. This isn't a
prompt: it's just a demonstration of moving the cursor on screen, using
colour to emphasize what has been done.

Save this in a file called "clock":
#!/bin/bash                                                                  
                                                                             
function prompt_command {                                                    
let prompt_x=$COLUMNS-5                                                      
}                                                                            
                                                                             
PROMPT_COMMAND=prompt_command                                                
                                                                             
function clock {                                                             
local       BLUE="\[\033[0;34m\]"                                            
local        RED="\[\033[0;31m\]"                                            
local  LIGHT_RED="\[\033[1;31m\]"                                            
local      WHITE="\[\033[1;37m\]"                                            
local  NO_COLOUR="\[\033[0m\]"                                               
case $TERM in                                                                
    xterm*)                                                                  
        TITLEBAR='\[\033]0;\u@\h:\w\007\]'                                   
        ;;                                                                   
    *)                                                                       
        TITLEBAR=""                                                          
        ;;                                                                   
esac                                                                         
                                                                             
PS1="${TITLEBAR}\                                                            
\[\033[s\033[1;\$(echo -n \${prompt_x})H\]\                                  
$BLUE[$LIGHT_RED\$(date +%H%M)$BLUE]\[\033[u\033[1A\]                        
$BLUE[$LIGHT_RED\u@\h:\w$BLUE]\                                              
$WHITE\$$NO_COLOUR "                                                         
PS2='> '                                                                     
PS4='+ '                                                                     
}                                                                            

This prompt is fairly plain, except that it keeps a 24 hour clock in the
upper right corner of the terminal (even if the terminal is resized). This
will NOT work on the terminal emulators that I mentioned that don't accept
the save and restore cursor position codes. If you try to run this prompt in
any of those terminal emulators, the clock will appear correctly, but the
prompt will be trapped on the second line of the terminal.

See also Section 12.9 for a more extensive use of these codes.
-----------------------------------------------------------------------------

6.3. Xterm Title Bar Manipulations

I'm not sure that these escape sequences strictly qualify as "ANSI Escape
Sequences," but in practice their use is almost identical so I've included
them in this chapter. 

Non-printing escape sequences can be used to produce interesting effects in
prompts. To use these escape sequences, you need to enclose them in \[ and \]
(as discussed in Section 3.4, telling Bash to ignore this material while
calculating the size of the prompt. Failing to include these delimiters
results in line editing code placing the cursor incorrectly because it
doesn't know the actual size of the prompt. Escape sequences must also be
preceded by \033[ in Bash prior to version 2, or by either \033[ or \e[ in
later versions.  

If you try to change the title bar of your Xterm with your prompt when you're
at the console, you'll produce garbage in your prompt. To avoid this, test
the TERM environment variable to tell if your prompt is going to be in an
Xterm. 
function proml                                                               
{                                                                            
case $TERM in                                                                
    xterm*)                                                                  
        local TITLEBAR='\[\033]0;\u@\h:\w\007\]'                             
        ;;                                                                   
    *)                                                                       
        local TITLEBAR=''                                                    
        ;;                                                                   
esac                                                                         
                                                                             
PS1="${TITLEBAR}\                                                            
[\$(date +%H%M)]\                                                            
[\u@\h:\w]\                                                                  
\$ "                                                                         
PS2='> '                                                                     
PS4='+ '                                                                     
}                                                                            

This is a function that can be incorporated into ~/.bashrc. The function name
could then be called to execute the function. The function, like the PS1
string, is stored in the environment. Once the PS1 string is set by the
function, you can remove the function from the environment with unset proml.
Since the prompt can't change from being in an Xterm to being at the console,
the TERM variable isn't tested every time the prompt is generated. I used
continuation markers (backslashes) in the definition of the prompt, to allow
it to be continued on multiple lines. This improves readability, making it
easier to modify and debug.

The first step in creating this prompt is to test if the shell we're starting
is an xterm or not: if it is, the shell variable (${TITLEBAR}) is defined. It
consists of the appropriate escape sequences, and \u@\h:\w, which puts <user>
@<machine>:<working directory> in the Xterm title bar. This is particularly
useful with minimized Xterms, making them more rapidly identifiable. The
other material in this prompt should be familiar from previous prompts we've
created.  

The only drawback to manipulating the Xterm title bar like this occurs when
you log into a system on which you haven't set up the title bar hack: the
Xterm will continue to show the information from the previous system that had
the title bar hack in place. 

A suggestion from Charles Lepple (<clepple at negativezero dot org>) on
setting the window title of the Xterm and the title of the corresponding icon
separately. He uses this under WindowMaker because the title that's
appropriate for an Xterm is usually too long for a 64x64 icon. "\[\e]1;
icon-title\007\e]2;main-title\007\]". He says to set this in the prompt
command because "I tried putting the string in PS1, but it causes flickering
under some window managers because it results in setting the prompt multiple
times when you are editing a multi-line command (at least under bash 1.4.x --
and I was too lazy to fully explore the reasons behind it)." I had no trouble
with it in the PS1 string, but didn't use any multi-line commands. He also
points out that it works under xterm, xwsh, and dtterm, but not
gnome-terminal (which uses only the main title). I also found it to work with
rxvt, but not kterm.  
-----------------------------------------------------------------------------

6.4. Xterm Title Bars and Screen

Non-screen users should skip this section. Of course, screen is an awesome
program and what you should really do is rush out and find out what screen is
- if you've read this far in the HOWTO, you're enough of a Command Line
Interface Junkie that you need to know. 

If you use screen in Xterms and you want to manipulate the title bar, your
life may just have become a bit more complicated ... Screen can, but doesn't
automatically, treat the Xterm title bar as a hardstatus line (whatever that
means, but it's where we put our Xterm title). If you're a RedHat user,
you'll probably find the following line in your ~/.screenrc: 
+---------------------------------------------------------------------------+
|        termcapinfo xterm 'hs:ts=\E]2;:fs=\007:ds=\E]2;screen\007'         |
+---------------------------------------------------------------------------+

If that line isn't in there, you should put it in. This allows the titlebar
manipulations in the previous section to work under Xterm. But I found they
failed when I used rxvt. I e-mailed a question about this to the screen
maintainers, and Michael Schroeder (one of those good people labouring behind
the scenes to make free Unix/Linux software as great as it is) told me to add
the following to my ~/.screenrc: 
+---------------------------------------------------------------------------+
|        termcapinfo rxvt 'hs:ts=\E]2;:fs=\007:ds=\E]2;screen\007'          |
+---------------------------------------------------------------------------+

I don't know if this will work for other Xterm variants, but since the two
lines are functionally identical except for the name of the Xterm type,
perhaps ... I leave this as an exercise for the reader. It did fix my
problem, although I haven't researched further to see if it interferes with
the icon-titlebar naming distinction. 
-----------------------------------------------------------------------------

6.5. Colours and Cursor Movement With tput

As with so many things in Unix, there is more than one way to achieve the
same ends. A utility called tput can also be used to move the cursor around
the screen, get back information about the status of the terminal, or set
colours. man tput doesn't go into much detail about the available commands,
but Emilio Lopes e-mailed me to point out that man terminfo will give you a 
huge list of capabilities, many of which are device independent, and
therefore better than the escape sequences previously mentioned. He suggested
that I rewrite all the examples using tput for this reason. He is correct
that I should, but I've had some trouble controlling it and getting it to do
everything I want it to. However, I did rewrite one prompt which you can see
as an example: Section 12.8. 

Here is a list of tput capabilities that I have found useful:

tput Colour Capabilities

tput setab [1-7]
    Set a background colour using ANSI escape
   
tput setb [1-7]
    Set a background colour
   
tput setaf [1-7]
    Set a foreground colour using ANSI escape
   
tput setf [1-7]
    Set a foreground colour
   

tput Text Mode Capabilities

tput bold
    Set bold mode
   
tput dim
    turn on half-bright mode
   
tput smul
    begin underline mode
   
tput rmul
    exit underline mode
   
tput rev
    Turn on reverse mode
   
tput smso
    Enter standout mode (bold on rxvt)
   
tput rmso
    Exit standout mode
   
tput sgr0
    Turn off all attributes (doesn't work quite as expected)
   

tput Cursor Movement Capabilities

tput cup Y X
    Move cursor to screen location X,Y (top left is 0,0)
   
tput sc
    Save the cursor position
   
tput rc
    Restore the cursor position
   
tput lines
    Output the number of lines of the terminal
   
tput cols
    Output the number of columns of the terminal
   
tput cub N
    Move N characters left
   
tput cuf N
    Move N characters right
   
tput cub1
    move left one space
   
tput cuf1
    non-destructive space (move right one space)
   
tput ll
    last line, first column (if no cup)
   
tput cuu1
    up one line
   

tput Clear and Insert Capabilities

tput ech N
    Erase N characters
   
tput clear
    clear screen and home cursor
   
tput el1
    Clear to beginning of line
   
tput el
    clear to end of line
   
tput ed
    clear to end of screen
   
tput ich N
    insert N characters (moves rest of line forward!)
   
tput il N
    insert N lines
   

This is by no means a complete list of what terminfo and tput allow, in fact
it's only the beginning. man tput and man terminfo if you want to know more.
-----------------------------------------------------------------------------

Chapter 7. Special Characters: Octal Escape Sequences

Outside of the characters that you can type on your keyboard, there are a lot
of other characters you can print on your screen. I've created a script to
allow you to check out what the font you're using has available for you. The
main command you need to use to utilize these characters is "echo -e". The
"-e" switch tells echo to enable interpretation of backslash-escaped
characters. What you see when you look at octal 200-400 will be very
different with a VGA font from what you will see with a standard Linux font.
Be warned that some of these escape sequences have odd effects on your
terminal, and I haven't tried to prevent them from doing whatever they do.
The linedraw and block characters that are used heavily by the Bashprompt
project are between octal 260 and 337 in the VGA fonts.
#!/bin/bash                                                                     
                                                                                
#   Script: escgen                                                              
                                                                                
function usage {                                                                
   echo -e "\033[1;34mescgen\033[0m <lower_octal_value> [<higher_octal_value>]" 
   echo "   Octal escape sequence generator: print all octal escape sequences"  
   echo "   between the lower value and the upper value.  If a second value"    
   echo "   isn't supplied, print eight characters."                            
   echo "   1998 - Giles Orr, no warranty."                                     
   exit 1                                                                       
}                                                                               
                                                                                
if [ "$#" -eq "0" ]                                                             
then                                                                            
   echo -e "\033[1;31mPlease supply one or two values.\033[0m"                  
   usage                                                                        
fi                                                                              
let lower_val=${1}                                                              
if [ "$#" -eq "1" ]                                                             
then                                                                            
   #   If they don't supply a closing value, give them eight characters.        
   upper_val=$(echo -e "obase=8 \n ibase=8 \n $lower_val+10 \n quit" | bc)      
else                                                                            
   let upper_val=${2}                                                           
fi                                                                              
if [ "$#" -gt "2" ]                                                             
then                                                                            
   echo -e "\033[1;31mPlease supply two values.\033[0m"                         
   echo                                                                         
   usage                                                                        
fi                                                                              
if [ "${lower_val}" -gt "${upper_val}" ]                                        
then                                                                            
   echo -e "\033[1;31m${lower_val} is larger than ${upper_val}."                
   echo                                                                         
   usage                                                                        
fi                                                                              
if [ "${upper_val}" -gt "777" ]                                                 
   then                                                                         
   echo -e "\033[1;31mValues cannot exceed 777.\033[0m"                         
   echo                                                                         
   usage                                                                        
fi                                                                              
                                                                                
let i=$lower_val                                                                
let line_count=1                                                                
let limit=$upper_val                                                            
while [ "$i" -lt "$limit" ]                                                     
do                                                                              
   octal_escape="\\$i"                                                          
   echo -en "$i:'$octal_escape' "                                               
   if [ "$line_count" -gt "7" ]                                                 
   then                                                                         
      echo                                                                      
      #   Put a hard return in.                                                 
      let line_count=0                                                          
   fi                                                                           
   let i=$(echo -e "obase=8 \n ibase=8 \n $i+1 \n quit" | bc)                   
   let line_count=$line_count+1                                                 
done                                                                            
echo                                                                            

You can also use xfd to display all the characters in an X font, with the
command xfd -fn <fontname>. Clicking on any given character will give you
lots of information about that character, including its octal value. The
script given above will be useful on the console, and if you aren't sure of
the current font name.
-----------------------------------------------------------------------------

Chapter 8. The Bash Prompt Package

8.1. Availability

The Bash Prompt package was available at [http://bash.current.nu/] http://
bash.current.nu/, and is the work of several people, co-ordinated by Rob
Current (aka BadLandZ). The site was down in July 2001, but Rob Current
assures me it will be back up soon. The package is in beta, but offers a
simple way of using multiple prompts (or themes), allowing you to set prompts
for login shells, and for subshells (ie. putting PS1 strings in ~
/.bash_profile and ~/.bashrc). Most of the themes use the extended VGA
character set, so they look bad unless they're used with VGA fonts (which
aren't the default on most systems). Little work has been done on this
project recently: I hope there's some more progress. 
-----------------------------------------------------------------------------

8.2. Xterm Fonts

To use some of the most attractive prompts in the Bash Prompt package, you
need to get and install fonts that support the character sets expected by the
prompts. These are "VGA Fonts," which support different character sets than
regular Xterm fonts. Standard Xterm fonts support an extended alphabet,
including a lot of letters with accents. In VGA fonts, this material is
replaced by graphical characters - blocks, dots, lines. I asked for an
explanation of this difference, and Sérgio Vale e Pace (space@gold.com.br)
wrote me:

   
    I love computer history so here goes:
   
    When IBM designed the first PC they needed some character codes to use,
    so they got the ASCII character table (128 numbers, letters, and some
    punctuation) and to fill a byte addressed table they added 128 more
    characters. Since the PC was designed to be a home computer, they fill
    the remaining 128 characters with dots, lines, points, etc, to be able to
    do borders, and grayscale effects (remember that we are talking about 2
    color graphics).
   
    Time passes, PCs become a standard, IBM creates more powerful systems and
    the VGA standard is born, along with 256 colour graphics, and IBM
    continues to include their IBM-ASCII characters table.
   
    More time passes, IBM has lost their leadership in the PC market, and the
    OS authors dicover that there are other languages in the world that use
    non-english characters, so they add international alphabet support in
    their systems. Since we now have bright and colorful screens, we can
    trash the dots, lines, etc. and use their space for accented characters
    and some greek letters, which you'll see in Linux.
   
-----------------------------------------------------------------------------
8.3. Changing the Xterm Font

Getting and installing these fonts is a somewhat involved process. First,
retrieve the font(s). Next, ensure they're .pcf or .pcf.gz files. If they're
.bdf files, investigate the "bdftopcf" command (ie. read the man page). Drop
the .pcf or .pcf.gz files into the /usr/X11R6/lib/X11/fonts/misc dir (this is
the correct directory for RedHat 5.1 through 7.1, it may be different on
other distributions). cd to that directory, and run mkfontdir. Then run xset
fp rehash and/or restart your X font server, whichever applies to your
situation. Sometimes it's a good idea to go into the fonts.alias file in the
same directory, and create shorter alias names for the fonts.

To use the new fonts, you start your Xterm program of choice with the
appropriate command to your Xterm, which can be found either in the man page
or by using the "--help" parameter on the command line. Popular terms would
be used as follows:
+---------------------------------------------------------------------------+
|xterm -font <fontname>                                                     |
+---------------------------------------------------------------------------+

OR
+---------------------------------------------------------------------------+
|xterm -fn <fontname> -fb <fontname-bold>                                   |
|Eterm -F <fontname>                                                        |
|rxvt -fn <fontname>                                                        |
+---------------------------------------------------------------------------+

VGA fonts are available from Stumpy's ANSI Fonts page at [http://
home.earthlink.net/~us5zahns/enl/ansifont.html] http://home.earthlink.net/
~us5zahns/enl/ansifont.html (which I have borrowed from extensively while
writing this).
-----------------------------------------------------------------------------

8.4. Line Draw Characters without VGA Fonts

Xterm and rxvt can be switched into line-draw mode on the fly with the
appropriate escape sequence. You'll need to switch back after you've output
the characters you wanted or any text following it will be garbled. Prompts
based on these output codes don't work on the console, instead producing the
text equivalents. 

To start a sequence of line draw characters, use an echo -e and the \033(0
escape sequence. Most of the characters worth using are in the range lower
case "a" through "z". Terminate the string with another escape sequence, \033
(B . 

The best method I've found for testing this is shown in the image below: use
the escgen script mentioned earlier in the HOWTO to show the 100 to 200 octal
range, echo the first escape sequence, run the escgen script for the same
range, and echo the closing escape sequence. The image also shows how to use
this in a prompt. 

[rxvt-line-draw]

Using escape sequences in RXVT (also works in Xterm and RXVT derivatives like
aterm, which is used here) to produce line draw characters. The "escgen"
script used above is given earlier in the HOWTO. 
-----------------------------------------------------------------------------

Chapter 9. Loading a Different Prompt

9.1. Loading a Different Prompt, Later

The explanations in this HOWTO have shown how to make PS1 environment
variables, or how to incorporate those PS1 and PS2 strings into functions
that could be called by ~/.bashrc or as a theme by the bashprompt package.

Using the bashprompt package, you would type bashprompt -i to see a list of
available themes. To set the prompt in future login shells (primarily the
console, but also telnet and Xterms, depending on how your Xterms are set
up), you would type bashprompt -l themename. bashprompt then modifies your ~
/.bash_profile to call the requested theme when it starts. To set the prompt
in future subshells (usually Xterms, rxvt, etc.), you type bashprompt -s
themename, and bashprompt modifies your ~/.bashrc file to call the
appropriate theme at startup.  

See also Section 2.6 for Johan Kullstam's note regarding the importance of
putting the PS? strings in ~/.bashrc .
-----------------------------------------------------------------------------

9.2. Loading a Different Prompt, Immediately

You can change the prompt in your current terminal (using the example "elite"
function above) by typing source elite followed by elite (assuming that the
elite function file is the working directory). This is somewhat cumbersome,
and leaves you with an extra function (elite) in your environment space - if
you want to clean up the environment, you would have to type unset elite as
well. This would seem like an ideal candidate for a small shell script, but a
script doesn't work here because the script cannot change the environment of
your current shell: it can only change the environment of the subshell it
runs in. As soon as the script stops, the subshell goes away, and the changes
the script made to the environment are gone. What can change environment
variables of your current shell are environment functions. The bashprompt
package puts a function called callbashprompt into your environment, and,
while they don't document it, it can be called to load any bashprompt theme
on the fly. It looks in the theme directory it installed (the theme you're
calling has to be there), sources the function you asked for, loads the
function, and then unsets the function, thus keeping your environment
uncluttered. callbashprompt wasn't intended to be used this way, and has no
error checking, but if you keep that in mind, it works quite well. 
-----------------------------------------------------------------------------

9.3. Loading Different Prompts in Different X Terms

If you have a specific prompt to go with a particular project, or some reason
to load different prompts at different times, you can use multiple bashrc
files instead of always using your ~/.bashrc file. The Bash command is
something like bash --rcfile /home/giles/.bashprompt/bashrc/bashrcdan, which
will start a new version of Bash in your current terminal. To use this in
combination with a Window Manager menuing system, use a command like rxvt -e
bash --rcfile /home/giles/.bashprompt/bashrc/bashrcdan. The exact command you
use will be dependent on the syntax of your X term of choice and the location
of the bashrc file you're using. 
-----------------------------------------------------------------------------

Chapter 10. Loading Prompt Colours Dynamically

10.1. A "Proof of Concept" Example

This is a "proof of concept" more than an attractive prompt: changing colours
within the prompt dynamically. In this example, the colour of the host name
changes depending on the load (as a warning).
#!/bin/bash                                                                                   
#   "hostloadcolour" - 17 October 98, by Giles                                                
#                                                                                             
#   The idea here is to change the colour of the host name in the prompt,                     
#   depending on a threshold load value.                                                      
                                                                                              
# THRESHOLD_LOAD is the value of the one minute load (multiplied                              
# by one hundred) at which you want                                                           
# the prompt to change from COLOUR_LOW to COLOUR_HIGH                                         
THRESHOLD_LOAD=200                                                                            
COLOUR_LOW='1;34'                                                                             
          # light blue                                                                        
COLOUR_HIGH='1;31'                                                                            
           # light red                                                                        
                                                                                              
function prompt_command {                                                                     
ONE=$(uptime | sed -e "s/.*load average: \(.*\...\), \(.*\...\), \(.*\...\)/\1/" -e "s/ //g") 
#   Apparently, "scale" in bc doesn't apply to multiplication, but does                       
#   apply to division.                                                                        
ONEHUNDRED=$(echo -e "scale=0 \n $ONE/0.01 \nquit \n" | bc)                                   
if [ $ONEHUNDRED -gt $THRESHOLD_LOAD ]                                                        
then                                                                                          
    HOST_COLOUR=$COLOUR_HIGH                                                                  
        # Light Red                                                                           
else                                                                                          
    HOST_COLOUR=$COLOUR_LOW                                                                   
        # Light Blue                                                                          
fi                                                                                            
}                                                                                             
                                                                                              
function hostloadcolour {                                                                     
                                                                                              
PROMPT_COMMAND=prompt_command                                                                 
PS1="[$(date +%H%M)][\u@\[\033[\$(echo -n \$HOST_COLOUR)m\]\h\[\033[0m\]:\w]$ "               
}                                                                                             

Using your favorite editor, save this to a file named "hostloadcolour". If
you have the Bashprompt package installed, this will work as a theme. If you
don't, type source hostloadcolour and then hostloadcolour. Either way,
"prompt_command" becomes a function in your environment. If you examine the
code, you will notice that the colours ($COLOUR_HIGH and $COLOUR_LOW) are set
using only a partial colour code, ie. "1;34" instead of "\[\033[1;34m\]",
which I would have preferred. I have been unable to get it to work with the
complete code. Please let me know if you manage this.
-----------------------------------------------------------------------------

Chapter 11. Prompt Code Snippets

This section shows how to put various pieces of information into the Bash
prompt. There are an infinite number of things that could be put in your
prompt. Feel free to send me examples, I'll try to include what I think will
be most widely used. If you have an alternate way to retrieve a piece of
information here, and feel your method is more efficient, please contact me.
It's easy to write bad code, I do it often, but it's great to write elegant
code, and a pleasure to read it. I manage it every once in a while, and would
love to have more of it to put in here. 

To incorporate shell code in prompts, it has to be escaped. Usually, this
will mean putting it inside \$(<command>) so that the output of command is
substituted each time the prompt is generated. 

Please keep in mind that I develop and test this code on a single user 900
MHz Athlon with 256 meg of RAM, so the delay generated by these code snippets
doesn't usually mean much to me. To help with this, I recently assembled a 25
MHz 486 SX with 16 meg of RAM, and you will see the output of the "time"
command for each snippet to indicate how much of a delay it causes on a
slower machine. 
-----------------------------------------------------------------------------

11.1. Built-in Escape Sequences

See Section 2.5 for a complete list of built-in escape sequences. This list
is taken directly from the Bash man page, so you can also look there.
-----------------------------------------------------------------------------

11.2. Date and Time

If you don't like the built-ins for date and time, extracting the same
information from the date command is relatively easy. Examples already seen
in this HOWTO include date +%H%M, which will put in the hour in 24 hour
format, and the minute. date "+%A, %d %B %Y" will give something like
"Sunday, 06 June 1999". For a full list of the interpreted sequences, type 
date --help or man date.  

Relative speed: "date ..." takes about 0.12 seconds on an unloaded 486SX25. 
-----------------------------------------------------------------------------

11.3. Counting Files in the Current Directory

To determine how many files there are in the current directory, put in ls -1
| wc -l. This uses wc to do a count of the number of lines (-l) in the output
of ls -1. It doesn't count dotfiles. Please note that ls -l (that's an "L"
rather than a "1" as in the previous examples) which I used in previous
versions of this HOWTO will actually give you a file count one greater than
the actual count. Thanks to Kam Nejad for this point. 

If you want to count only files and NOT include symbolic links (just an
example of what else you could do), you could use ls -l | grep -v ^l | wc -l
(that's an "L" not a "1" this time, we want a "long" listing here). grep
checks for any line beginning with "l" (indicating a link), and discards that
line (-v). 

Relative speed: "ls -1 /usr/bin/ | wc -l" takes about 1.03 seconds on an
unloaded 486SX25 (/usr/bin/ on this machine has 355 files). "ls -l /usr/bin/
| grep -v ^l | wc -l" takes about 1.19 seconds. 
-----------------------------------------------------------------------------

11.4. Total Bytes in the Current Directory

If you want to know how much space the contents of the current directory take
up, you can use something like the following:
let TotalBytes=0                                                             
                                                                             
for Bytes in $(ls -l | grep "^-" | awk '{ print $5 }')                       
do                                                                           
   let TotalBytes=$TotalBytes+$Bytes                                         
done                                                                         
                                                                             
# The if...fi's give a more specific output in byte, kilobyte, megabyte,     
# and gigabyte                                                               
                                                                             
if [ $TotalBytes -lt 1024 ]; then                                            
   TotalSize=$(echo -e "scale=3 \n$TotalBytes \nquit" | bc)                  
   suffix="b"                                                                
elif [ $TotalBytes -lt 1048576 ]; then                                       
   TotalSize=$(echo -e "scale=3 \n$TotalBytes/1024 \nquit" | bc)             
   suffix="kb"                                                               
elif [ $TotalBytes -lt 1073741824 ]; then                                    
   TotalSize=$(echo -e "scale=3 \n$TotalBytes/1048576 \nquit" | bc)          
   suffix="Mb"                                                               
else                                                                         
   TotalSize=$(echo -e "scale=3 \n$TotalBytes/1073741824 \nquit" | bc)       
   suffix="Gb"                                                               
fi                                                                           
                                                                             
echo -n "${TotalSize}${suffix}"                                              

Code courtesy of me, Sam Schmit (<id at pt dot lu>), and Sam's uncle
Jean-Paul, who ironed out a fairly major bug in my original code, and just
generally cleaned it up. 

Note that you could also just use ls -l | grep ^total | awk '{ print $2 }'
because ls -l prints out a line at the beginning that is the approximate size
of the directory in kilobytes - although for reasons unknown to me, it seems
to be less accurate (but obviously faster) than the above script. 

Relative speed: this process takes between 3.2 and 5.8 seconds in /usr/bin/
(14.7 meg in the directory) on an unloaded 486SX25, depending on how much of
the information is cached (if you use this in a prompt, more or less of it
will be cached depending how long you work in the directory). 
-----------------------------------------------------------------------------

11.5. Checking the Current TTY

The tty command returns the filename of the terminal connected to standard
input. This comes in two formats on the Linux systems I have used, either "/
dev/tty4" or "/dev/pts/2". I've used several methods over time, but the
simplest I've found so far (probably both Linux- and Bash-2.x specific) is 
temp=$(tty) ; echo ${temp:5}. This removes the first five characters of the 
tty output, in this case "/dev/". 

Previously, I used tty | sed -e "s:/dev/::", which removes the leading "/dev/
". Older systems (in my experience, RedHat through 5.2) returned only
filenames in the "/dev/tty4" format, so I used tty | sed -e "s/.*tty\(.*\)/\1
/".  

An alternative method: ps ax | grep $$ | awk '{ print $2 }'.

Relative speed: the ${temp:5} method takes about 0.12 seconds on an unloaded
486SX25, the sed-driven method takes about 0.19 seconds, the awk-driven
method takes about 0.79 seconds. 
-----------------------------------------------------------------------------

11.6. Stopped Jobs Count

Torben Fjerdingstad (<tfj at fjerdingstad dot dk>) wrote to tell me that he
often stops jobs and then forgets about them. He uses his prompt to remind
himself of stopped jobs. Apparently this is fairly popular, because as of
Bash 2.04, there is a standard escape sequence for jobs managed by the shell:
+---------------------------------------------------------------------------+
|[giles@zinfandel]$ export PS1='\W[\j]\$ '                                  |
|giles[0]$ man ls &                                                         |
|[1] 31899                                                                  |
|giles[1]$ xman &                                                           |
|[2] 31907                                                                  |
|                                                                           |
|[1]+  Stopped                 man ls                                       |
|giles[2]$ jobs                                                             |
|[1]+  Stopped                 man ls                                       |
|[2]-  Running                 xman &                                       |
|giles[2]$                                                                  |
+---------------------------------------------------------------------------+

Note that this shows both stopped and running jobs. At the console, you
probably want the complete count, but in an xterm you're probably only
interested in the ones that are stopped. To display only these, you could use
something like the following:
+---------------------------------------------------------------------------+
|[giles@zinfandel]$ function stoppedjobs {                                  |
|-- jobs -s | wc -l | sed -e "s/ //g"                                       |
|-- }                                                                       |
|[giles@zinfandel]$ export PS1='\W[`stoppedjobs`]\$ '                       |
|giles[0]$ jobs                                                             |
|giles[0]$ man ls &                                                         |
|[1] 32212                                                                  |
|                                                                           |
|[1]+  Stopped                 man ls                                       |
|giles[0]$ man X &                                                          |
|[2] 32225                                                                  |
|                                                                           |
|[2]+  Stopped                 man X                                        |
|giles[2]$ jobs                                                             |
|[1]-  Stopped                 man ls                                       |
|[2]+  Stopped                 man X                                        |
|giles[2]$ xman &                                                           |
|[3] 32246                                                                  |
|giles[2]$ sleep 300 &                                                      |
|[4] 32255                                                                  |
|giles[2]$ jobs                                                             |
|[1]-  Stopped                 man ls                                       |
|[2]+  Stopped                 man X                                        |
|[3]   Running                 xman &                                       |
|[4]   Running                 sleep 300 &                                  |
+---------------------------------------------------------------------------+

This doesn't always show the stopped job in the prompt that follows
immediately after the command is executed - it probably depends on whether
the job is launched and put in the background before jobs is run.

Note There is a known bug in Bash 2.02 that causes the jobs command (a shell 
     builtin) to return nothing to a pipe. If you try the above under Bash   
     2.02, you will always get a "0" back regardless of how many jobs you    
     have stopped. This problem is fixed in 2.03.                            

Relative speed: 'jobs -s | wc -l | sed -e "s/ //g" ' takes about 0.24 seconds
on an unloaded 486SX25. 
-----------------------------------------------------------------------------

11.7. Load

The output of uptime can be used to determine both the system load and
uptime, but its output is exceptionally difficult to parse. On a Linux
system, this is made much easier to deal with by the existence of the /proc/
file system. cat /proc/loadavg will show you the one minute, five minute, and
fifteen minute load average, as well as a couple other numbers I don't know
the meaning of (anyone care to fill me in?). 

Getting the load from /proc/loadavg is easy (thanks to Jerry Peek for
reminding me of this simple method): read one five fifteen rest < /proc/
loadavg. Just print the value you want. 

For those without the /proc/ filesystem, you can use uptime | sed -e "s/.*
load average: \(.*\...\), \(.*\...\), \(.*\...\)/\1/" -e "s/ //g" and replace
"\1" with "\2" or "\3" depending if you want the one minute, five minute, or
fifteen minute load average. This is a remarkably ugly regular expression:
send suggestions if you have a better one. 

Relative speed: 'uptime | sed -e "s/.*load average: \(.*\...\), \(.*\...\), \
(.*\...\)/\1/" -e "s/ //g" ' takes about 0.21 seconds on an unloaded 486SX25.
-----------------------------------------------------------------------------

11.8. Uptime

As with load, the data available through uptime is very difficult to parse.
Again, if you have the /proc/ filesystem, take advantage of it. I wrote the
following code to output just the time the system has been up: 
+---------------------------------------------------------------------------+
|#!/bin/bash                                                                |
|#                                                                          |
|#   upt - show just the system uptime, days, hours, and minutes            |
|                                                                           |
|let upSeconds="$(cat /proc/uptime) && echo ${temp%%.*})"                   |
|let secs=$((${upSeconds}%60))                                              |
|let mins=$((${upSeconds}/60%60))                                           |
|let hours=$((${upSeconds}/3600%24))                                        |
|let days=$((${upSeconds}/86400))                                           |
|if [ "${days}" -ne "0" ]                                                   |
|then                                                                       |
|   echo -n "${days}d"                                                      |
|fi                                                                         |
|echo -n "${hours}h${mins}m"                                                |
+---------------------------------------------------------------------------+

Output looks like "1h31m" if the system has been up less than a day, or
"14d17h3m" if it has been up more than a day. You can massage the output to
look the way you want it to. This evolved after an e-mail discussion with
David Osolkowski, who gave me some ideas. 

Before I wrote that script, I had a couple emails with David O, who said "me
and a couple guys got on irc and started hacking with sed and got this: 
uptime | sed -e 's/.* \(.* days,\)\? \(.*:..,\) .*/\1 \2/' -e's/,//g' -e 's/
days/d/' -e 's/ up //'. It's ugly, and doesn't use regex nearly as well as it
should, but it works. It's pretty slow on a P75, though, so I removed it."
Considering how much uptime output varies depending on how long a system has
been up, I was impressed they managed as well as they did. You can use this
on systems without /proc/ filesystem, but as he says, it may be slow. 

Relative speed: the "upt" script takes about 0.68 seconds on an unloaded
486SX25 (half that as a function). Contrary to David's guess, his use of sed
to parse the output of "uptime" takes only 0.22 seconds. 
-----------------------------------------------------------------------------

11.9. Number of Processes

ps ax | wc -l | tr -d " " OR ps ax | wc -l | awk '{print $1}' OR ps ax | wc
-l | sed -e "s: ::g". In each case, tr or awk or sed is used to remove the
undesirable whitespace.

Relative speed: any one of these variants takes about 0.9 seconds on an
unloaded 486SX25. 
-----------------------------------------------------------------------------

11.10. Controlling the Size and Appearance of $PWD

Unix allows long file names, which can lead to the value of $PWD being very
long. Some people (notably the default RedHat prompt) choose to use the
basename of the current working directory (ie. "giles" if $PWD="/home/
giles"). I like more info than that, but it's often desirable to limit the
length of the directory name, and it makes the most sense to truncate on the
left.
#   How many characters of the $PWD should be kept                           
local pwdmaxlen=30                                                           
#   Indicator that there has been directory truncation:                      
#trunc_symbol="<"                                                            
local trunc_symbol="..."                                                     
if [ ${#PWD} -gt $pwdmaxlen ]                                                
then                                                                         
        local pwdoffset=$(( ${#PWD} - $pwdmaxlen ))                          
        newPWD="${trunc_symbol}${PWD:$pwdoffset:$pwdmaxlen}"                 
else                                                                         
        newPWD=${PWD}                                                        
fi                                                                           

The above code can be executed as part of PROMPT_COMMAND, and the environment
variable generated (newPWD) can then be included in the prompt. Thanks to
Alexander Mikhailian <mikhailian at altern dot org> who rewrote the code to
utilize new Bash functionality, thus speeding it up considerably. 

Risto Juola (risto AT risto.net) wrote to say that he preferred to have the
"~" in the $newPWD, so he wrote another version: 
pwd_length=20                                                                
                                                                             
DIR=`pwd`                                                                    
                                                                             
echo $DIR | grep "^$HOME" >> /dev/null                                       
                                                                             
if [ $? -eq 0 ]                                                              
then                                                                         
  CURRDIR=`echo $DIR | awk -F$HOME '{print $2}'`                             
  newPWD="~$CURRDIR"                                                         
                                                                             
  if [ $(echo -n $newPWD | wc -c | tr -d " ") -gt $pwd_length ]              
  then                                                                       
    newPWD="~/..$(echo -n $PWD | sed -e "s/.*\(.\{$pwd_length\}\)/\1/")"     
  fi                                                                         
elif [ "$DIR" = "$HOME" ]                                                    
then                                                                         
  newPWD="~"                                                                 
elif [ $(echo -n $PWD | wc -c | tr -d " ") -gt $pwd_length ]                 
then                                                                         
  newPWD="..$(echo -n $PWD | sed -e "s/.*\(.\{$pwd_length\}\)/\1/")"         
else                                                                         
  newPWD="$(echo -n $PWD)"                                                   
fi                                                                           

Relative speed: the first version takes about 0.45 seconds on an unloaded
486SX25. Risto's version takes about 0.80 to 0.95 seconds. The variation in
this case is due to whether or not truncation is required. 
-----------------------------------------------------------------------------

11.11. Laptop Power

If you have a laptop with APM installed, try the following PROMPT_COMMAND to
create an environment variable ${battery} you can add to your prompt. This
will indicate if AC power is connected and percentage power remaining. AC
power is indicated by a "^" (for on) and a "v" (for off) before the
percentage value. 
function prompt_command {                                                    
        #  As much of the response of the "apm" command as is                
        #  necessary to identify the given condition:                        
   NO_AC_MESG="AC off"                                                       
   AC_MESG="AC on"                                                           
                                                                             
   APMD_RESPONSE="$(apm)"                                                    
   case ${APMD_RESPONSE} in                                                  
      *${AC_MESG}*)                                                          
         ACstat="^"                                                          
         ;;                                                                  
      *${NO_AC_MESG}*)                                                       
         ACstat="v"                                                          
         ;;                                                                  
   esac                                                                      
                                                                             
   battery="${temp##* }"                                                     
   battery="${ACstat}${battery}"                                             
}                                                                            
-----------------------------------------------------------------------------

11.12. Having the Prompt Ignored on Cut and Paste

This one is weird but cool. Rory Toma <rory at corp dot webtv dot net> wrote
to suggest a prompt like this: : rory@demon ; . How is this useful? You can
triple click on any previous command (in Linux, anyway) to highlight the
whole line, then paste that line in front of another prompt and the stuff
between the ":" and the """ is ignored, like so: 
: rory@demon ; uptime                                                        
  5:15pm  up 6 days, 23:04,  2 users,  load average: 0.00, 0.00, 0.00        
: rory@demon ; : rory@demon ; uptime                                         
  5:15pm  up 6 days, 23:04,  2 users,  load average: 0.00, 0.00, 0.00        

The prompt is a no-op, and if your PS2 is set to a space, multiple lines can
be cut and pasted as well.
-----------------------------------------------------------------------------

11.13. New Mail

Several people have sent me methods for checking whether or not they had new
e-mail. Most of them relied on programs that aren't on every system. Then I
received the following code from Henrik Veenpere: cat $MAIL |grep -c ^
Message-. This is simple and elegant, and I like it. 
-----------------------------------------------------------------------------

11.14. Prompt Beeps After Long-Running Commands

Robb Matzke (matzke at llnl dot gov) sent me this a long time ago (sorry
Robb, should have put it in sooner!). This prompt uses Perl and the builtin 
times command to determine if the program that just finished running has used
more than a certain amount of time. The assumption is that you might have
changed desktops by then and notification would be nice, so it rings a bell.
I've tried to avoid using Perl because the overhead is fairly high, but this
is a good use for it. 

I haven't tested this prompt myself. I like the idea though. Robb includes
instructions in the comments. 
#!/usr/bin/perl                                                                 
require 5.003;                                                                  
use strict;                                                                     
                                                                                
############################################################################### 
# prompt_bell -- execute arbitrary commands contingent upon CPU time            
#                                                                               
# Copyright (C) 2000 Robb Matzke                                                
#                                                                               
#    This program is free software; you can redistribute it and/or modify it    
#    under the terms of the GNU General Public License as published by the      
#    Free Software Foundation; either version 2 of the License, or (at your     
#    option) any later version.                                                 
#                                                                               
#    This program is distributed in the hope that it will be useful, but        
#    WITHOUT ANY WARRANTY; without even the implied warranty of                 
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General  
#    Public License for more details.                                           
#                                                                               
#    You should have received a copy of the GNU General Public License along    
#    with this program; see the file COPYING.  If not, write to the Free        
#    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA         
#    02111-1307, USA.                                                           
#                                                                               
# Purpose:                                                                      
#                                                                               
#    This program is intended to be called each time a shell prompt is          
#    displayed. It looks at current CPU times (user+system) for the shell and   
#    its children, and if the CPU time is more than some user-specified amount  
#    then user-specified commands are executed.  The author uses it to provide  
#    an audio indication of when a long-running command completes.              
#                                                                               
# Usage:                                                                        
#                                                                               
#    The prompt_bell command takes two arguments: the name of a file            
#    containing the latest CPU usage information for the shell and its          
#    children, and some optional state information from the environment         
#    variable $PROMPT_BELL_STATE.                                               
#                                                                               
#    The times file simply contains one or more times, zero or more to a line,  
#    each of the form `#h#m#.#s' where `#' is a sequence of one or more         
#    decimal digits and `#h' is the optional number of hours, `#m' is the       
#    required number of minutes, and `#.#s' is the number of seconds and        
#    fractions thereof. The total time is the sum of all the times in this      
#    file. Example:                                                             
#                                                                               
#        0m0.050s 0m0.060s                                                      
#        0m15.790s 0m0.220s                                                     
#                                                                               
#    The output from this command is one or more semicolon-separated shell      
#    commands which should be eval'd by the caller. If the difference between   
#    the current CPU times and the previous CPU times (stored in environment    
#    variable PROMPT_BELL_STATE) is more than $PROMPT_BELL_TIME seconds         
#    (default 10) then the commands printed include the value of environment    
#    variable PROMPT_BELL_CMD (default is "echo -ne '\a'").                     
#                                                                               
#    Typical usage is:                                                          
#        eval "`prompt_bell $TIMES_FILE $PROMPT_BELL_STATE`"                    
#                                                                               
#    and this command is usually part of the bash PROMPT_COMMAND. The author's  
#    .bashrc contains the following:                                            
#                                                                               
#        PROMPT_BELL_TIME=15                                                    
#        PROMPT_BELL_CMD="echo -e 'done.\a'"                                    
#                                                                               
#        COMMAND_PROMPT='TIMES_FILE=/tmp/times.$$;                              
#                        times >$TIMES_FILE;                                    
#                        eval "`prompt_bell $TIMES_FILE $PROMPT_BELL_STATE`";   
#                        /bin/rm -f $TIMES_FILE'                                
#        export PROMPT_BELL_TIME PROMPT_BELL_CMD COMMAND_PROMPT                 
#                                                                               
#    Note: the output of `times' is stored in a temporary file to prevent it    
#    from being executed in a subshell whose CPU times are always nearly zero.  
#                                                                               
##############################################################################  
                                                                                
# Convert #h#m#s to seconds.                                                    
sub seconds {                                                                   
  my($hms) = @_;                                                                
  my($h,$m,$s) = $hms =~ /^(?:(\d+)h)?(\d+)m(\d+\.\d+)s/;                       
  return $h*3600 + $m*60 + $s;                                                  
}                                                                               
                                                                                
# Obtain processor times in seconds                                             
my $times_file = shift;                                                         
my $ptime_cur = 0;                                                              
open TIMES_FILE, $times_file or die "prompt_bell: $times_file: $!\n";           
while (<TIMES_FILE>) {                                                          
  s/(?:(\d+)h)?(\d+)m(\d+(?:\.\d+)?)s/$ptime_cur+=$1*3600+$2*60+$3/eg;          
}                                                                               
close TIMES_FILE;                                                               
                                                                                
                                                                                
# Obtain previous state to compute deltas.                                      
my $ptime_prev = shift;                                                         
                                                                                
# If the processor time was more than $PROMPT_BELL_TIME or 10 seconds           
# then beep.                                                                    
my $beep;                                                                       
my $limit = exists $ENV{PROMPT_BELL_TIME}?$ENV{PROMPT_BELL_TIME}:10;            
if ($ptime_cur-$ptime_prev>$limit) {                                            
  $beep = ";" . ($ENV{PROMPT_BELL_CMD} || "echo -ne '\\a'");                    
}                                                                               
                                                                                
# Generate the shell commands                                                   
print "PROMPT_BELL_STATE=$ptime_cur$beep\n";                                    
exit 0;                                                                         
-----------------------------------------------------------------------------

Chapter 12. Example Prompts

12.1. Examples on the Web

Over time, many people have e-mailed me excellent examples, and I've written
some interesting ones myself. There are too many to include here, so I have
put all of the examples together into some web pages which can be seen at
[http://www.gilesorr.com/bashprompt/] http://www.gilesorr.com/bashprompt/.
Most of the examples given here can also be seen on the web. 
-----------------------------------------------------------------------------

12.2. A "Lightweight" Prompt

function proml {                                                             
local BLUE="\[\033[0;34m\]"                                                  
local RED="\[\033[0;31m\]"                                                   
local LIGHT_RED="\[\033[1;31m\]"                                             
local WHITE="\[\033[1;37m\]"                                                 
local NO_COLOUR="\[\033[0m\]"                                                
case $TERM in                                                                
    xterm*|rxvt*)                                                            
        TITLEBAR='\[\033]0;\u@\h:\w\007\]'                                   
        ;;                                                                   
    *)                                                                       
        TITLEBAR=""                                                          
        ;;                                                                   
esac                                                                         
                                                                             
PS1="${TITLEBAR}\                                                            
$BLUE[$RED\$(date +%H%M)$BLUE]\                                              
$BLUE[$LIGHT_RED\u@\h:\w$BLUE]\                                              
$WHITE\$$NO_COLOUR "                                                         
PS2='> '                                                                     
PS4='+ '                                                                     
}                                                                            

[proml]

The lightweight proml prompt, showing time, username, machine name, and
working directory in colour. It also modifies the title of the terminal. 
-----------------------------------------------------------------------------

12.3. Dan's Prompt

Dan was a coworker of mine at the university I work at for a while. Dan used
csh and tcsh for a long time before moving to Bash, so he uses the history
number a lot. He uses "screen" a lot, and for that, it's helpful to have the
tty. The last part of his prompt is the return value of the last executed
command. Dan doesn't like having the $PWD in his prompt because it makes the
prompt grow and shrink too much. 
#!/bin/bash                                                                  
#   Dan's prompt looks like this:                                            
#      543,p3,0$                                                             
#                                                                            
PROMPT_COMMAND=""                                                            
function dan {                                                               
local cur_tty=$(temp=$(tty) ; echo ${temp:5});                               
PS1="\!,$cur_tty,\$?\$ "                                                     
}                                                                            

[dan]

Dan's prompt: history number, tty number, return value of the last executed
function. 
-----------------------------------------------------------------------------

12.4. Elite from Bashprompt Themes

Note that this requires a VGA font.
# Created by KrON from windowmaker on IRC                                        
# Changed by Spidey 08/06                                                        
function elite {                                                                 
PS1="\[\033[31m\]\332\304\[\033[34m\](\[\033[31m\]\u\[\033[34m\]@\[\033[31m\]\h\ 
\[\033[34m\])\[\033[31m\]-\[\033[34m\](\[\033[31m\]\$(date +%I:%M%P)\            
\[\033[34m\]-:-\[\033[31m\]\$(date +%m)\[\033[34m\033[31m\]/\$(date +%d)\        
\[\033[34m\])\[\033[31m\]\304-\[\033[34m]\\371\[\033[31m\]-\371\371\             
\[\033[34m\]\372\n\[\033[31m\]\300\304\[\033[34m\](\[\033[31m\]\W\[\033[34m\])\  
\[\033[31m\]\304\371\[\033[34m\]\372\[\033[00m\]"                                
PS2="> "                                                                         
}                                                                                

[elite]

The elite prompt from the Bashprompt Themes. 
-----------------------------------------------------------------------------

12.5. A "Power User" Prompt

I actually did use this prompt for a while, but it results in noticeable
delays in the appearance of the prompt on a single-user PII-400, so I
wouldn't recommend using it on a multi-user P-100 or anything ... A rewrite
using newer Bash functionality might help, but look at it for ideas rather
than as a practical prompt. 

#!/bin/bash                                                                                                                               
#----------------------------------------------------------------------                                                                   
#       POWER USER PROMPT "pprom2"                                                                                                        
#----------------------------------------------------------------------                                                                   
#                                                                                                                                         
#   Created August 98, Last Modified 9 November 98 by Giles                                                                               
#                                                                                                                                         
#   Problem: when load is going down, it says "1.35down-.08", get rid                                                                     
#   of the negative                                                                                                                       
                                                                                                                                          
function prompt_command                                                                                                                   
{                                                                                                                                         
#   Create TotalMeg variable: sum of visible file sizes in current directory                                                              
local TotalBytes=0                                                                                                                        
for Bytes in $(ls -l | grep "^-" | awk '{print $5}')                                                                                      
do                                                                                                                                        
    let TotalBytes=$TotalBytes+$Bytes                                                                                                     
done                                                                                                                                      
TotalMeg=$(echo -e "scale=3 \nx=$TotalBytes/1048576\n if (x<1) {print \"0\"} \n print x \nquit" | bc)                                     
                                                                                                                                          
#      This is used to calculate the differential in load values                                                                          
#      provided by the "uptime" command.  "uptime" gives load                                                                             
#      averages at 1, 5, and 15 minute marks.                                                                                             
#                                                                                                                                         
local one=$(uptime | sed -e "s/.*load average: \(.*\...\), \(.*\...\), \(.*\...\)/\1/" -e "s/ //g")                                       
local five=$(uptime | sed -e "s/.*load average: \(.*\...\), \(.*\...\), \(.*\...\).*/\2/" -e "s/ //g")                                    
local diff1_5=$(echo -e "scale = scale ($one) \nx=$one - $five\n if (x>0) {print \"up\"} else {print \"down\"}\n print x \nquit \n" | bc) 
loaddiff="$(echo -n "${one}${diff1_5}")"                                                                                                  
                                                                                                                                          
#   Count visible files:                                                                                                                  
let files=$(ls -l | grep "^-" | wc -l | tr -d " ")                                                                                        
let hiddenfiles=$(ls -l -d .* | grep "^-" | wc -l | tr -d " ")                                                                            
let executables=$(ls -l | grep ^-..x | wc -l | tr -d " ")                                                                                 
let directories=$(ls -l | grep "^d" | wc -l | tr -d " ")                                                                                  
let hiddendirectories=$(ls -l -d .* | grep "^d" | wc -l | tr -d " ")-2                                                                    
let linktemp=$(ls -l | grep "^l" | wc -l | tr -d " ")                                                                                     
if [ "$linktemp" -eq "0" ]                                                                                                                
then                                                                                                                                      
    links=""                                                                                                                              
else                                                                                                                                      
    links=" ${linktemp}l"                                                                                                                 
fi                                                                                                                                        
unset linktemp                                                                                                                            
let devicetemp=$(ls -l | grep "^[bc]" | wc -l | tr -d " ")                                                                                
if [ "$devicetemp" -eq "0" ]                                                                                                              
then                                                                                                                                      
    devices=""                                                                                                                            
else                                                                                                                                      
    devices=" ${devicetemp}bc"                                                                                                            
fi                                                                                                                                        
unset devicetemp                                                                                                                          
                                                                                                                                          
}                                                                                                                                         
                                                                                                                                          
PROMPT_COMMAND=prompt_command                                                                                                             
                                                                                                                                          
function pprom2 {                                                                                                                         
                                                                                                                                          
local        BLUE="\[\033[0;34m\]"                                                                                                        
local  LIGHT_GRAY="\[\033[0;37m\]"                                                                                                        
local LIGHT_GREEN="\[\033[1;32m\]"                                                                                                        
local  LIGHT_BLUE="\[\033[1;34m\]"                                                                                                        
local  LIGHT_CYAN="\[\033[1;36m\]"                                                                                                        
local      YELLOW="\[\033[1;33m\]"                                                                                                        
local       WHITE="\[\033[1;37m\]"                                                                                                        
local         RED="\[\033[0;31m\]"                                                                                                        
local   NO_COLOUR="\[\033[0m\]"                                                                                                           
                                                                                                                                          
case $TERM in                                                                                                                             
    xterm*)                                                                                                                               
        TITLEBAR='\[\033]0;\u@\h:\w\007\]'                                                                                                
        ;;                                                                                                                                
    *)                                                                                                                                    
        TITLEBAR=""                                                                                                                       
        ;;                                                                                                                                
esac                                                                                                                                      
                                                                                                                                          
PS1="$TITLEBAR\                                                                                                                           
$BLUE[$RED\$(date +%H%M)$BLUE]\                                                                                                           
$BLUE[$RED\u@\h$BLUE]\                                                                                                                    
$BLUE[\                                                                                                                                   
$LIGHT_GRAY\${files}.\${hiddenfiles}-\                                                                                                    
$LIGHT_GREEN\${executables}x \                                                                                                            
$LIGHT_GRAY(\${TotalMeg}Mb) \                                                                                                             
$LIGHT_BLUE\${directories}.\                                                                                                              
\${hiddendirectories}d\                                                                                                                   
$LIGHT_CYAN\${links}\                                                                                                                     
$YELLOW\${devices}\                                                                                                                       
$BLUE]\                                                                                                                                   
$BLUE[${WHITE}\${loaddiff}$BLUE]\                                                                                                         
$BLUE[\                                                                                                                                   
$WHITE\$(ps ax | wc -l | sed -e \"s: ::g\")proc\                                                                                          
$BLUE]\                                                                                                                                   
\n\                                                                                                                                       
$BLUE[$RED\$PWD$BLUE]\                                                                                                                    
$WHITE\$\                                                                                                                                 
\                                                                                                                                         
$NO_COLOUR "                                                                                                                              
PS2='> '                                                                                                                                  
PS4='+ '                                                                                                                                  
}                                                                                                                                         
-----------------------------------------------------------------------------

12.6. Prompt Depending on Connection Type

Bradley M Alexander (storm@tux.org) had the excellent idea of reminding his
users what kind of connection they were using to his machine(s), so he
colour-codes prompts dependent on connection type. Here's the bashrc he
supplied to me:
# /etc/bashrc                                                                
                                                                             
# System wide functions and aliases                                          
# Environment stuff goes in /etc/profile                                     
                                                                             
# For some unknown reason bash refuses to inherit                            
# PS1 in some circumstances that I can't figure out.                         
# Putting PS1 here ensures that it gets loaded every time.                   
                                                                             
# Set up prompts. Color code them for logins. Red for root, white for        
# user logins, green for ssh sessions, cyan for telnet,                      
# magenta with red "(ssh)" for ssh + su, magenta for telnet.                 
THIS_TTY=tty`ps aux | grep $$ | grep bash | awk '{ print $7 }'`              
SESS_SRC=`who | grep $THIS_TTY | awk '{ print $6 }'`                         
                                                                             
SSH_FLAG=0                                                                   
SSH_IP=`echo $SSH_CLIENT | awk '{ print $1 }'`                               
if [ $SSH_IP ] ; then                                                        
  SSH_FLAG=1                                                                 
fi                                                                           
SSH2_IP=`echo $SSH2_CLIENT | awk '{ print $1 }'`                             
if [ $SSH2_IP ] ; then                                                       
  SSH_FLAG=1                                                                 
fi                                                                           
if [ $SSH_FLAG -eq 1 ] ; then                                                
  CONN=ssh                                                                   
elif [ -z $SESS_SRC ] ; then                                                 
  CONN=lcl                                                                   
elif [ $SESS_SRC = "(:0.0)" -o $SESS_SRC = "" ] ; then                       
  CONN=lcl                                                                   
else                                                                         
  CONN=tel                                                                   
fi                                                                           
                                                                             
# Okay...Now who we be?                                                      
if [ `/usr/bin/whoami` = "root" ] ; then                                     
  USR=priv                                                                   
else                                                                         
  USR=nopriv                                                                 
fi                                                                           
                                                                             
#Set some prompts...                                                         
if [ $CONN = lcl -a $USR = nopriv ] ; then                                   
  PS1="[\u \W]\\$ "                                                          
elif [ $CONN = lcl -a $USR = priv ] ; then                                   
  PS1="\[\033[01;31m\][\w]\\$\[\033[00m\] "                                  
elif [ $CONN = tel -a $USR = nopriv ] ; then                                 
  PS1="\[\033[01;34m\][\u@\h \W]\\$\[\033[00m\] "                            
elif [ $CONN = tel -a $USR = priv ] ; then                                   
  PS1="\[\033[01;30;45m\][\u@\h \W]\\$\[\033[00m\] "                         
elif [ $CONN = ssh -a $USR = nopriv ] ; then                                 
  PS1="\[\033[01;32m\][\u@\h \W]\\$\[\033[00m\] "                            
elif [ $CONN = ssh -a $USR = priv ] ; then                                   
  PS1="\[\033[01;35m\][\u@\h \W]\\$\[\033[00m\] "                            
fi                                                                           
                                                                             
# PS1="[\u@\h \W]\\$ "                                                       
export PS1                                                                   
alias which="type -path"                                                     
alias dir="ls -lF --color"                                                   
alias dirs="ls -lFS --color"                                                 
alias h=history                                                              
-----------------------------------------------------------------------------

12.7. A Prompt the Width of Your Term

A friend complained that he didn't like having a prompt that kept changing
size because it had $PWD in it, so I wrote this prompt that adjusts its size
to exactly the width of your term, with the working directory on the top line
of two.
#!/bin/bash                                                                                                                                                
#   termwide prompt with tty number                                                                                                                        
#      by Giles - created 2 November 98, last tweaked 31 July 2001                                                                                         
#                                                                                                                                                          
#     This is a variant on "termwide" that incorporates the tty number.                                                                                    
#                                                                                                                                                          
                                                                                                                                                           
hostnam=$(hostname -s)                                                                                                                                     
usernam=$(whoami)                                                                                                                                          
temp="$(tty)"                                                                                                                                              
#   Chop off the first five chars of tty (ie /dev/):                                                                                                       
cur_tty="${temp:5}"                                                                                                                                        
unset temp                                                                                                                                                 
                                                                                                                                                           
function prompt_command {                                                                                                                                  
                                                                                                                                                           
#   Find the width of the prompt:                                                                                                                          
TERMWIDTH=${COLUMNS}                                                                                                                                       
                                                                                                                                                           
#   Add all the accessories below ...                                                                                                                      
local temp="--(${usernam}@${hostnam}:${cur_tty})---(${PWD})--"                                                                                             
                                                                                                                                                           
let fillsize=${TERMWIDTH}-${#temp}                                                                                                                         
if [ "$fillsize" -gt "0" ]                                                                                                                                 
then                                                                                                                                                       
        fill="-------------------------------------------------------------------------------------------------------------------------------------------" 
        #   It's theoretically possible someone could need more                                                                                            
        #   dashes than above, but very unlikely!  HOWTO users,                                                                                            
        #   the above should be ONE LINE, it may not cut and                                                                                               
        #   paste properly                                                                                                                                 
        fill="${fill:0:${fillsize}}"                                                                                                                       
        newPWD="${PWD}"                                                                                                                                    
fi                                                                                                                                                         
                                                                                                                                                           
if [ "$fillsize" -lt "0" ]                                                                                                                                 
then                                                                                                                                                       
        fill=""                                                                                                                                            
        let cut=3-${fillsize}                                                                                                                              
        newPWD="...${PWD:${cut}}"                                                                                                                          
fi                                                                                                                                                         
}                                                                                                                                                          
                                                                                                                                                           
PROMPT_COMMAND=prompt_command                                                                                                                              
                                                                                                                                                           
function twtty {                                                                                                                                           
                                                                                                                                                           
local WHITE="\[\033[1;37m\]"                                                                                                                               
local NO_COLOUR="\[\033[0m\]"                                                                                                                              
                                                                                                                                                           
local LIGHT_BLUE="\[\033[1;34m\]"                                                                                                                          
local YELLOW="\[\033[1;33m\]"                                                                                                                              
                                                                                                                                                           
case $TERM in                                                                                                                                              
    xterm*|rxvt*)                                                                                                                                          
        TITLEBAR='\[\033]0;\u@\h:\w\007\]'                                                                                                                 
        ;;                                                                                                                                                 
    *)                                                                                                                                                     
        TITLEBAR=""                                                                                                                                        
        ;;                                                                                                                                                 
esac                                                                                                                                                       
                                                                                                                                                           
PS1="$TITLEBAR\                                                                                                                                            
$YELLOW-$LIGHT_BLUE-(\                                                                                                                                     
$YELLOW\$usernam$LIGHT_BLUE@$YELLOW\$hostnam$LIGHT_BLUE:$WHITE\$cur_tty\                                                                                   
${LIGHT_BLUE})-${YELLOW}-\${fill}${LIGHT_BLUE}-(\                                                                                                          
$YELLOW\${newPWD}\                                                                                                                                         
$LIGHT_BLUE)-$YELLOW-\                                                                                                                                     
\n\                                                                                                                                                        
$YELLOW-$LIGHT_BLUE-(\                                                                                                                                     
$YELLOW\$(date +%H%M)$LIGHT_BLUE:$YELLOW\$(date \"+%a,%d %b %y\")\                                                                                         
$LIGHT_BLUE:$WHITE\$$LIGHT_BLUE)-\                                                                                                                         
$YELLOW-\                                                                                                                                                  
$NO_COLOUR "                                                                                                                                               
                                                                                                                                                           
PS2="$LIGHT_BLUE-$YELLOW-$YELLOW-$NO_COLOUR "                                                                                                              
                                                                                                                                                           
}                                                                                                                                                          
                                                                                                                                                           

[twtty]

The twtty prompt in action. 
-----------------------------------------------------------------------------

12.8. The Floating Clock Prompt

I've rewritten this prompt several times. It was originally written using
octal escape sequences, but the ones I needed most for this (save and restore
cursor position) aren't honoured by one of the commonest terminal emulators,
rxvt. I rewrote it using tput, and that's what you see here. The required 
tput codes seem to be universally honoured. The body of the prompt is
essentially the same as the "Lightweight" prompt shown earlier, but a clock
is kept floating in the upper right corner of the term. It will reposition
itself correctly even if the term is resized. 
#!/bin/bash                                                                  
                                                                             
#   Rewrite of "clock" using tput                                            
                                                                             
function prompt_command {                                                    
#  prompt_x is where to position the cursor to write the clock               
let prompt_x=$(tput cols)-6                                                  
#  Move up one; not sure why we need to do this, but without this, I always  
#  got an extra blank line between prompts                                   
tput cuu1                                                                    
tput sc                                                                      
tput cup 0 ${prompt_x}                                                       
tput setaf 4 ; tput bold                                                     
echo -n "["                                                                  
tput setaf 1                                                                 
echo -n "$(date +%H%M)"                                                      
tput setaf 4 ; tput bold                                                     
echo -n "]"                                                                  
tput rc                                                                      
}                                                                            
                                                                             
PROMPT_COMMAND=prompt_command                                                
                                                                             
function clockt {                                                            
local       BLUE="\[$(tput setaf 4 ; tput bold)\]"                           
local  LIGHT_RED="\[$(tput setaf 1 ; tput bold)\]"                           
local      WHITE="\[$(tput setaf 7 ; tput bold)\]"                           
local  NO_COLOUR="\[$(tput sgr0)\]"                                          
case $TERM in                                                                
    xterm*|rxvt*)                                                            
        TITLEBAR='\[\033]0;\u@\h:\w\007\]'                                   
        ;;                                                                   
    *)                                                                       
        TITLEBAR=""                                                          
        ;;                                                                   
esac                                                                         
                                                                             
PS1="${TITLEBAR}\                                                            
$BLUE[$LIGHT_RED\u@\h:\w$BLUE]\                                              
$WHITE\$$NO_COLOUR "                                                         
PS2='> '                                                                     
PS4='+ '                                                                     
}                                                                            

[clockt]

The floating clock prompt in action. The clock will stay in correct position
even if the term is resized. 
-----------------------------------------------------------------------------

12.9. The Elegant Useless Clock Prompt

This is one of the more attractive (and useless) prompts I've made. Because
many X terminal emulators don't implement cursor position save and restore,
the alternative when putting a clock in the upper right corner is to anchor
the cursor at the bottom of the terminal. This builds on the idea of the
"termwide" prompt above, drawing a line up the right side of the screen from
the prompt to the clock. A VGA font is required.

Note: There is an odd substitution in here, that may not print properly being
translated from SGML to other formats: I had to substitute the screen
character for \304 - I would normally have just included the sequence "\304",
but it was necessary to make this substitution in this case.
#!/bin/bash                                                                    
                                                                               
#   This prompt requires a VGA font.  The prompt is anchored at the bottom     
#   of the terminal, fills the width of the terminal, and draws a line up      
#   the right side of the terminal to attach itself to a clock in the upper    
#   right corner of the terminal.                                              
                                                                               
function prompt_command {                                                      
#   Calculate the width of the prompt:                                         
hostnam=$(echo -n $HOSTNAME | sed -e "s/[\.].*//")                             
#   "whoami" and "pwd" include a trailing newline                              
usernam=$(whoami)                                                              
newPWD="${PWD}"                                                                
#   Add all the accessories below ...                                          
let promptsize=$(echo -n "--(${usernam}@${hostnam})---(${PWD})-----" \         
                 | wc -c | tr -d " ")                                          
#   Figure out how much to add between user@host and PWD (or how much to       
#   remove from PWD)                                                           
let fillsize=${COLUMNS}-${promptsize}                                          
fill=""                                                                        
#   Make the filler if prompt isn't as wide as the terminal:                   
while [ "$fillsize" -gt "0" ]                                                  
do                                                                             
   fill="${fill}Ä"                                                             
   # The A with the umlaut over it (it will appear as a long dash if           
   # you're using a VGA font) is \304, but I cut and pasted it in              
   # because Bash will only do one substitution - which in this case is        
   # putting $fill in the prompt.                                              
   let fillsize=${fillsize}-1                                                  
done                                                                           
#   Right-truncate PWD if the prompt is going to be wider than the terminal:   
if [ "$fillsize" -lt "0" ]                                                     
then                                                                           
   let cutt=3-${fillsize}                                                      
   newPWD="...$(echo -n $PWD | sed -e "s/\(^.\{$cutt\}\)\(.*\)/\2/")"          
fi                                                                             
#                                                                              
#   Create the clock and the bar that runs up the right side of the term       
#                                                                              
local LIGHT_BLUE="\033[1;34m"                                                  
local     YELLOW="\033[1;33m"                                                  
#   Position the cursor to print the clock:                                    
echo -en "\033[2;$((${COLUMNS}-9))H"                                           
echo -en "$LIGHT_BLUE($YELLOW$(date +%H%M)$LIGHT_BLUE)\304$YELLOW\304\304\277" 
local i=${LINES}                                                               
echo -en "\033[2;${COLUMNS}H"                                                  
#   Print vertical dashes down the side of the terminal:                       
while [ $i -ge 4 ]                                                             
do                                                                             
   echo -en "\033[$(($i-1));${COLUMNS}H\263"                                   
   let i=$i-1                                                                  
done                                                                           
                                                                               
let prompt_line=${LINES}-1                                                     
#   This is needed because doing \${LINES} inside a Bash mathematical          
#   expression (ie. $(())) doesn't seem to work.                               
}                                                                              
                                                                               
PROMPT_COMMAND=prompt_command                                                  
                                                                               
function clock3 {                                                              
local LIGHT_BLUE="\[\033[1;34m\]"                                              
local     YELLOW="\[\033[1;33m\]"                                              
local      WHITE="\[\033[1;37m\]"                                              
local LIGHT_GRAY="\[\033[0;37m\]"                                              
local  NO_COLOUR="\[\033[0m\]"                                                 
                                                                               
case $TERM in                                                                  
    xterm*)                                                                    
        TITLEBAR='\[\033]0;\u@\h:\w\007\]'                                     
        ;;                                                                     
    *)                                                                         
        TITLEBAR=""                                                            
        ;;                                                                     
esac                                                                           
                                                                               
PS1="$TITLEBAR\                                                                
\[\033[\${prompt_line};0H\]                                                    
$YELLOW\332$LIGHT_BLUE\304(\                                                   
$YELLOW\${usernam}$LIGHT_BLUE@$YELLOW\${hostnam}\                              
${LIGHT_BLUE})\304${YELLOW}\304\${fill}${LIGHT_BLUE}\304(\                     
$YELLOW\${newPWD}\                                                             
$LIGHT_BLUE)\304$YELLOW\304\304\304\331\                                       
\n\                                                                            
$YELLOW\300$LIGHT_BLUE\304(\                                                   
$YELLOW\$(date \"+%a,%d %b %y\")\                                              
$LIGHT_BLUE:$WHITE\$$LIGHT_BLUE)\304\                                          
$YELLOW\304\                                                                   
$LIGHT_GRAY "                                                                  
                                                                               
PS2="$LIGHT_BLUE\304$YELLOW\304$YELLOW\304$NO_COLOUR "                         
                                                                               
}                                                                              
-----------------------------------------------------------------------------

Appendix A. GNU Free Documentation License

Version 1.1, March 2000

   
    Copyright (C) 2000 Free Software Foundation, Inc. 59 Temple Place, Suite
    330, Boston, MA 02111-1307 USA Everyone is permitted to copy and
    distribute verbatim copies of this license document, but changing it is
    not allowed.
   
-----------------------------------------------------------------------------
0. PREAMBLE

The purpose of this License is to make a manual, textbook, or other written
document "free" in the sense of freedom: to assure everyone the effective
freedom to copy and redistribute it, with or without modifying it, either
commercially or noncommercially. Secondarily, this License preserves for the
author and publisher a way to get credit for their work, while not being
considered responsible for modifications made by others.

This License is a kind of "copyleft", which means that derivative works of
the document must themselves be free in the same sense. It complements the
GNU General Public License, which is a copyleft license designed for free
software.

We have designed this License in order to use it for manuals for free
software, because free software needs free documentation: a free program
should come with manuals providing the same freedoms that the software does.
But this License is not limited to software manuals; it can be used for any
textual work, regardless of subject matter or whether it is published as a
printed book. We recommend this License principally for works whose purpose
is instruction or reference.
-----------------------------------------------------------------------------

1. APPLICABILITY AND DEFINITIONS

This License applies to any manual or other work that contains a notice
placed by the copyright holder saying it can be distributed under the terms
of this License. The "Document", below, refers to any such manual or work.
Any member of the public is a licensee, and is addressed as "you".

A "Modified Version" of the Document means any work containing the Document
or a portion of it, either copied verbatim, or with modifications and/or
translated into another language.

A "Secondary Section" is a named appendix or a front-matter section of the
Document that deals exclusively with the relationship of the publishers or
authors of the Document to the Document's overall subject (or to related
matters) and contains nothing that could fall directly within that overall
subject. (For example, if the Document is in part a textbook of mathematics,
a Secondary Section may not explain any mathematics.) The relationship could
be a matter of historical connection with the subject or with related
matters, or of legal, commercial, philosophical, ethical or political
position regarding them.

The "Invariant Sections" are certain Secondary Sections whose titles are
designated, as being those of Invariant Sections, in the notice that says
that the Document is released under this License.

The "Cover Texts" are certain short passages of text that are listed, as
Front-Cover Texts or Back-Cover Texts, in the notice that says that the
Document is released under this License.

A "Transparent" copy of the Document means a machine-readable copy,
represented in a format whose specification is available to the general
public, whose contents can be viewed and edited directly and
straightforwardly with generic text editors or (for images composed of
pixels) generic paint programs or (for drawings) some widely available
drawing editor, and that is suitable for input to text formatters or for
automatic translation to a variety of formats suitable for input to text
formatters. A copy made in an otherwise Transparent file format whose markup
has been designed to thwart or discourage subsequent modification by readers
is not Transparent. A copy that is not "Transparent" is called "Opaque".

Examples of suitable formats for Transparent copies include plain ASCII
without markup, Texinfo input format, LaTeX input format, SGML or XML using a
publicly available DTD, and standard-conforming simple HTML designed for
human modification. Opaque formats include PostScript, PDF, proprietary
formats that can be read and edited only by proprietary word processors, SGML
or XML for which the DTD and/or processing tools are not generally available,
and the machine-generated HTML produced by some word processors for output
purposes only.

The "Title Page" means, for a printed book, the title page itself, plus such
following pages as are needed to hold, legibly, the material this License
requires to appear in the title page. For works in formats which do not have
any title page as such, "Title Page" means the text near the most prominent
appearance of the work's title, preceding the beginning of the body of the
text.
-----------------------------------------------------------------------------

2. VERBATIM COPYING

You may copy and distribute the Document in any medium, either commercially
or noncommercially, provided that this License, the copyright notices, and
the license notice saying this License applies to the Document are reproduced
in all copies, and that you add no other conditions whatsoever to those of
this License. You may not use technical measures to obstruct or control the
reading or further copying of the copies you make or distribute. However, you
may accept compensation in exchange for copies. If you distribute a large
enough number of copies you must also follow the conditions in section 3.

You may also lend copies, under the same conditions stated above, and you may
publicly display copies.
-----------------------------------------------------------------------------

3. COPYING IN QUANTITY

If you publish printed copies of the Document numbering more than 100, and
the Document's license notice requires Cover Texts, you must enclose the
copies in covers that carry, clearly and legibly, all these Cover Texts:
Front-Cover Texts on the front cover, and Back-Cover Texts on the back cover.
Both covers must also clearly and legibly identify you as the publisher of
these copies. The front cover must present the full title with all words of
the title equally prominent and visible. You may add other material on the
covers in addition. Copying with changes limited to the covers, as long as
they preserve the title of the Document and satisfy these conditions, can be
treated as verbatim copying in other respects.

If the required texts for either cover are too voluminous to fit legibly, you
should put the first ones listed (as many as fit reasonably) on the actual
cover, and continue the rest onto adjacent pages.

If you publish or distribute Opaque copies of the Document numbering more
than 100, you must either include a machine-readable Transparent copy along
with each Opaque copy, or state in or with each Opaque copy a
publicly-accessible computer-network location containing a complete
Transparent copy of the Document, free of added material, which the general
network-using public has access to download anonymously at no charge using
public-standard network protocols. If you use the latter option, you must
take reasonably prudent steps, when you begin distribution of Opaque copies
in quantity, to ensure that this Transparent copy will remain thus accessible
at the stated location until at least one year after the last time you
distribute an Opaque copy (directly or through your agents or retailers) of
that edition to the public.

It is requested, but not required, that you contact the authors of the
Document well before redistributing any large number of copies, to give them
a chance to provide you with an updated version of the Document.
-----------------------------------------------------------------------------

4. MODIFICATIONS

You may copy and distribute a Modified Version of the Document under the
conditions of sections 2 and 3 above, provided that you release the Modified
Version under precisely this License, with the Modified Version filling the
role of the Document, thus licensing distribution and modification of the
Modified Version to whoever possesses a copy of it. In addition, you must do
these things in the Modified Version:

 A. Use in the Title Page (and on the covers, if any) a title distinct from
    that of the Document, and from those of previous versions (which should,
    if there were any, be listed in the History section of the Document). You
    may use the same title as a previous version if the original publisher of
    that version gives permission.
   
 B. List on the Title Page, as authors, one or more persons or entities
    responsible for authorship of the modifications in the Modified Version,
    together with at least five of the principal authors of the Document (all
    of its principal authors, if it has less than five).
   
 C. State on the Title page the name of the publisher of the Modified
    Version, as the publisher.
   
 D. Preserve all the copyright notices of the Document.
   
 E. Add an appropriate copyright notice for your modifications adjacent to
    the other copyright notices.
   
 F. Include, immediately after the copyright notices, a license notice giving
    the public permission to use the Modified Version under the terms of this
    License, in the form shown in the Addendum below.
   
 G. Preserve in that license notice the full lists of Invariant Sections and
    required Cover Texts given in the Document's license notice.
   
 H. Include an unaltered copy of this License.
   
 I. Preserve the section entitled "History", and its title, and add to it an
    item stating at least the title, year, new authors, and publisher of the
    Modified Version as given on the Title Page. If there is no section
    entitled "History" in the Document, create one stating the title, year,
    authors, and publisher of the Document as given on its Title Page, then
    add an item describing the Modified Version as stated in the previous
    sentence.
   
 J. Preserve the network location, if any, given in the Document for public
    access to a Transparent copy of the Document, and likewise the network
    locations given in the Document for previous versions it was based on.
    These may be placed in the "History" section. You may omit a network
    location for a work that was published at least four years before the
    Document itself, or if the original publisher of the version it refers to
    gives permission.
   
 K. In any section entitled "Acknowledgements" or "Dedications", preserve the
    section's title, and preserve in the section all the substance and tone
    of each of the contributor acknowledgements and/or dedications given
    therein.
   
 L. Preserve all the Invariant Sections of the Document, unaltered in their
    text and in their titles. Section numbers or the equivalent are not
    considered part of the section titles.
   
 M. Delete any section entitled "Endorsements". Such a section may not be
    included in the Modified Version.
   
 N. Do not retitle any existing section as "Endorsements" or to conflict in
    title with any Invariant Section.
   

If the Modified Version includes new front-matter sections or appendices that
qualify as Secondary Sections and contain no material copied from the
Document, you may at your option designate some or all of these sections as
invariant. To do this, add their titles to the list of Invariant Sections in
the Modified Version's license notice. These titles must be distinct from any
other section titles.

You may add a section entitled "Endorsements", provided it contains nothing
but endorsements of your Modified Version by various parties--for example,
statements of peer review or that the text has been approved by an
organization as the authoritative definition of a standard.

You may add a passage of up to five words as a Front-Cover Text, and a
passage of up to 25 words as a Back-Cover Text, to the end of the list of
Cover Texts in the Modified Version. Only one passage of Front-Cover Text and
one of Back-Cover Text may be added by (or through arrangements made by) any
one entity. If the Document already includes a cover text for the same cover,
previously added by you or by arrangement made by the same entity you are
acting on behalf of, you may not add another; but you may replace the old
one, on explicit permission from the previous publisher that added the old
one.

The author(s) and publisher(s) of the Document do not by this License give
permission to use their names for publicity for or to assert or imply
endorsement of any Modified Version.
-----------------------------------------------------------------------------

5. COMBINING DOCUMENTS

You may combine the Document with other documents released under this
License, under the terms defined in section 4 above for modified versions,
provided that you include in the combination all of the Invariant Sections of
all of the original documents, unmodified, and list them all as Invariant
Sections of your combined work in its license notice.

The combined work need only contain one copy of this License, and multiple
identical Invariant Sections may be replaced with a single copy. If there are
multiple Invariant Sections with the same name but different contents, make
the title of each such section unique by adding at the end of it, in
parentheses, the name of the original author or publisher of that section if
known, or else a unique number. Make the same adjustment to the section
titles in the list of Invariant Sections in the license notice of the
combined work.

In the combination, you must combine any sections entitled "History" in the
various original documents, forming one section entitled "History"; likewise
combine any sections entitled "Acknowledgements", and any sections entitled
"Dedications". You must delete all sections entitled "Endorsements."
-----------------------------------------------------------------------------

6. COLLECTIONS OF DOCUMENTS

You may make a collection consisting of the Document and other documents
released under this License, and replace the individual copies of this
License in the various documents with a single copy that is included in the
collection, provided that you follow the rules of this License for verbatim
copying of each of the documents in all other respects.

You may extract a single document from such a collection, and distribute it
individually under this License, provided you insert a copy of this License
into the extracted document, and follow this License in all other respects
regarding verbatim copying of that document.
-----------------------------------------------------------------------------

7. AGGREGATION WITH INDEPENDENT WORKS

A compilation of the Document or its derivatives with other separate and
independent documents or works, in or on a volume of a storage or
distribution medium, does not as a whole count as a Modified Version of the
Document, provided no compilation copyright is claimed for the compilation.
Such a compilation is called an "aggregate", and this License does not apply
to the other self-contained works thus compiled with the Document, on account
of their being thus compiled, if they are not themselves derivative works of
the Document.

If the Cover Text requirement of section 3 is applicable to these copies of
the Document, then if the Document is less than one quarter of the entire
aggregate, the Document's Cover Texts may be placed on covers that surround
only the Document within the aggregate. Otherwise they must appear on covers
around the whole aggregate.
-----------------------------------------------------------------------------

8. TRANSLATION

Translation is considered a kind of modification, so you may distribute
translations of the Document under the terms of section 4. Replacing
Invariant Sections with translations requires special permission from their
copyright holders, but you may include translations of some or all Invariant
Sections in addition to the original versions of these Invariant Sections.
You may include a translation of this License provided that you also include
the original English version of this License. In case of a disagreement
between the translation and the original English version of this License, the
original English version will prevail.
-----------------------------------------------------------------------------

9. TERMINATION

You may not copy, modify, sublicense, or distribute the Document except as
expressly provided for under this License. Any other attempt to copy, modify,
sublicense or distribute the Document is void, and will automatically
terminate your rights under this License. However, parties who have received
copies, or rights, from you under this License will not have their licenses
terminated so long as such parties remain in full compliance.
-----------------------------------------------------------------------------

10. FUTURE REVISIONS OF THIS LICENSE

The Free Software Foundation may publish new, revised versions of the GNU
Free Documentation License from time to time. Such new versions will be
similar in spirit to the present version, but may differ in detail to address
new problems or concerns. See [http://www.gnu.org/copyleft/] http://
www.gnu.org/copyleft/.

Each version of the License is given a distinguishing version number. If the
Document specifies that a particular numbered version of this License "or any
later version" applies to it, you have the option of following the terms and
conditions either of that specified version or of any later version that has
been published (not as a draft) by the Free Software Foundation. If the
Document does not specify a version number of this License, you may choose
any version ever published (not as a draft) by the Free Software Foundation.
-----------------------------------------------------------------------------

How to use this License for your documents

To use this License in a document you have written, include a copy of the
License in the document and put the following copyright and license notices
just after the title page:

   
    Copyright (c) YEAR YOUR NAME. Permission is granted to copy, distribute
    and/or modify this document under the terms of the GNU Free Documentation
    License, Version 1.1 or any later version published by the Free Software
    Foundation; with the Invariant Sections being LIST THEIR TITLES, with the
    Front-Cover Texts being LIST, and with the Back-Cover Texts being LIST. A
    copy of the license is included in the section entitled "GNU Free
    Documentation License".
   
If you have no Invariant Sections, write "with no Invariant Sections" instead
of saying which ones are invariant. If you have no Front-Cover Texts, write
"no Front-Cover Texts" instead of "Front-Cover Texts being LIST"; likewise
for Back-Cover Texts.

If your document contains nontrivial examples of program code, we recommend
releasing these examples in parallel under your choice of free software
license, such as the GNU General Public License, to permit their use in free
software.
