LDP/LDP/howto/linuxdoc/Bash-Prompt-HOWTO.sgml

2322 lines
79 KiB
Plaintext
Raw Blame History

<!doctype linuxdoc system>
<article>
<title>Bash Prompt HOWTO
<author> Giles Orr,
<htmlurl url="mailto:giles@interlog.com" name="giles@interlog.com">
<date>v0.76 31 December 1999
<!-- CHANGELOG:
$Log$
Revision 0.76 1999/12/31 23:20:55 giles
Added Allen Huang, Chinese translator. Better tell him about it!
Revision 0.75 1999/12/19 23:23:40 giles
Changed Portugese translator to Mario Gamito.
Revision 0.74 1999/12/19 22:56:39 giles
Added Charles Lepple's code snippet for setting window title and icon
title separately.
Revision 0.73 1999/12/18 21:47:27 giles
Cleaned up tilde problem: Translators, note that I used a plain tilde
throughout, when I should have been using &tilde; - I have substituted
in <p> tags, where it seems to matter, but not in htmlurls or tscreens.
This was badly needed: the HOWTO used to tell you to put stuff in your
/.bashrc , because the leading tilde simply didn't print ...
Revision 0.72 1999/12/18 21:27:48 giles
Added Rory Toma's code snippet for cutting and pasting prompts.
Revision 0.71 1999/12/18 20:30:51 giles
Several clean-ups, added "code snippet" on file size in current directory.
Revision 0.70 1999/07/29 12:59:25 giles
Added Ellen Bokhorst as Dutch translator.
Revision 0.69 1999/07/11 02:05:51 giles
Clean-up throughout document. Probably make translator's jobs much
more difficult by including many small changes. Sorry.
Revision 0.68 1999/07/10 21:04:38 giles
Major change: most material related to Bash programming is now in its
own section. The section is mostly complete (except for "sourcing a
file"), but I need to clean up the places I removed the material from.
Revision 0.BLAH Lost logs from 0.65-0.67 - somehow the leading dollar
sign before "Log" went missing, so logging wasn't done.
Revision 0.64 1999/06/06 02:48:36 giles
Added pointer to web examples in the Examples section.
Revision 0.63 1999/06/06 02:19:19 giles
Bunch of minor textual revisions, plus ...
Revised two or three of the examples to excise the embarrassing
$PWD trimming method and go for \{$cut\} instead ...
Revision 0.62 1999/03/23 12:20:24 giles
Added Bradley Alexander's bashrc in Examples.
Revision 0.61 1999/03/23 00:45:57 giles
Several changes, mostly cosmetic. Added Sergio's history of fonts.
-->
<abstract>
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.
</abstract>
<toc>
<!-- ****************************************************** -->
<sect>Introduction and Administrivia
<sect1>Requirements
<p>
You will need Bash. The default version for most distributions is either
1.14.7, or 2.0.x. 1.14.7 was the standard for years, but is slowly being
replaced. I've been using Bash 2.0.x for quite a while now, but almost all
code presented here should work under 1.14.7. If I'm aware of a problem,
I'll mention it. You can check your Bash version by typing <TT>echo
$BASH_VERSION</TT> at the prompt. On my machine, it responds with
<TT>2.03.6(1)-release</TT>.
<p>
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.
<sect1>How To Use This Document
<p>
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.
<sect1>Translations
<p>
<em>Japanese:</em> <htmlurl
url="http://www.jf.linux.or.jp/JF/JF-ftp/other-formats/Bash-Prompt/Bash-Prompt-HOWTO.html"
name="http://www.jf.linux.or.jp/JF/JF-ftp/other-formats/Bash-Prompt/Bash-Prompt-HOWTO.html">,
provided by Akira Endo, <htmlurl url="mailto:akendo@t3.rim.or.jp"
name="akendo@t3.rim.or.jp">.
<p>
<em>German:</em> translation is in progress by Thomas
Keil, <htmlurl url="mailto:thomas@h-preissler.de"
name="thomas@h-preissler.de">.
<p>
<em>Italian:</em> by Daniel Dui,
<htmlurl url="ddui@iee.org" name="ddui@iee.org">,
available at <htmlurl url="http://www.crs4.it/~dui/linux.html"
name="http://www.crs4.it/~dui/linux.html">.
<p>
<em>Portugese:</em> translation is in progress by M<>rio Gamito, <htmlurl
url="mario.gamito@mail.telepac.pt" name="mario.gamito@mail.telepac.pt">.
<!--
Until mid-October 1999, it was these guys. With their and my agreement,
M<EFBFBD>rio Gamito took over.
<em>Portugese:</em> translation is in progress by Augusto Cardoso <htmlurl
url="cardoso.a@mail.telepac.pt" name="cardoso.a@mail.telepac.pt"> and Pedro
Almeida <htmlurl url="palmeida@gemini.ci.uc.pt"
name="palmeida@gemini.ci.uc.pt">.
-->
<p>
<em>Spanish:</em> translation by Iosu Santurt<72>n <htmlurl
url="iosu@bigfoot.com" name="iosu@bigfoot.com"> at <htmlurl
url="http://mipagina.euskaltel.es/iosus/linux/Bash-Prompt-HOWTO.html"
name="http://mipagina.euskaltel.es/iosus/linux/Bash-Prompt-HOWTO.html">.
<p>
<em>Dutch:</em> translation is in progress by Ellen Bokhorst <htmlurl
url="elboh@gironet.nl" name="elboh@gironet.nl">, and it will be available
at <htmlurl url="http://www.nl.linux.org/doc/HOWTO"
name="http://www.nl.linux.org/doc/HOWTO">.
<p>
<em>Chinese:</em> translation in progress by Allen Huang <htmlurl
url="lancelot@tomail.com.tw" name="lancelot@tomail.com.tw">. I will
include a URL when I have it.
<p>
Many thanks to all of them! URLs will be included as they're available.
<p>
If you are working on a translation, please notify me - especially if it's
available at a linkable URL. Thanks.
<sect1>Problems
<p>
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.
<itemize>
<item>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 <em>Learning the Bash Shell</em>, p.260-262.
<item>The terminal screen manager "screen" doesn't always get along with
ANSI colours. I'm not a screen expert, unfortunately. My current version
of screen (3.7.6-1, an RPM package) seems to work well in all cases, but
I've seen occasions where screen reduced all prompt colours to the standard
foreground colour in X terminals. This doesn't appear to be a problem on
the console.
<item>Xdefaults files can override colours. Look in &tilde;/.Xdefaults for
lines referring to XTerm*background and XTerm*foreground (or possibly
XTerm*Background and XTerm*Foreground).
<item>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.
<item>ANSI cursor movement escape sequences aren't all implemented in all X
terminals. That's discussed in its own section.
<item>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.
<item>Bash 2.0+ is out, and it incorporates some new features, and changes
some behaviour. Things that work under 1.14.7 don't necessarily work the
same under 2.0+, or vice versa.
</itemize>
<sect1>Send Me Comments and Suggestions
<p>
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've tried to check
suggestions I make against different versions of Bash (2.0x and 1.14.7),
but let me know of any incompatibilities you find.
<p>
The latest version of
this document should always be available at
<htmlurl url="http://www.interlog.com/~giles/bashprompt/"
name="http://www.interlog.com/~giles/bashprompt/">. Please check this
out, and feel free to e-mail me at
<htmlurl url="mailto:giles@interlog.com" name="giles@interlog.com"> with
suggestions.
<p>
I use the Linux Documentation Project HOWTOs almost exclusively in the HTML
format, so when I convert this from 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.
<sect1>Credits
<p>
In producing this document, I have borrowed heavily from the work of
the Bashprompt project at
<htmlurl url="http://bash.current.nu/" name="http://bash.current.nu/">. Other
sources used include the <em>xterm Title mini-HOWTO</em> by
Ric Lister, available at
<htmlurl url="http://sunsite.unc.edu/LDP/HOWTO/mini/Xterm-Title.html"
name="http://sunsite.unc.edu/LDP/HOWTO/mini/Xterm-Title.html">,
<em>Ansi Prompts</em> by Keebler, available at
<htmlurl url="http://www.ncal.verio.com/~keebler/ansi.html"
name="http://www.ncal.verio.com/~keebler/ansi.html">, <em>How to make
a Bash Prompt Theme</em> by Stephen Webb, available at
<htmlurl url="http://bash.current.nu/bash/HOWTO.html"
name="http://bash.current.nu/bash/HOWTO.html">, and <em>X ANSI Fonts</em>
by Stumpy, available at
<htmlurl url="http://home.earthlink.net/~us5zahns/enl/ansifont.html"
name="http://home.earthlink.net/~us5zahns/enl/ansifont.html">.
<p>Also of immense help were several conversations and e-mails from Dan,
an ex-co-worker at Georgia College & State University, whose knowledge
of Unix far exceeds mine. He's given me several excellent suggestions,
and ideas of his have led to some interesting prompts.
<p>
Three books that have been very useful while programming prompts are
<em>Linux in a Nutshell</em> by Jessica Heckman Perry (O'Reilly, 1997),
<em>Learning the Bash Shell</em> by Cameron Newham and Bill Rosenblatt
(O'Reilly, 2nd. ed., 1998) and <em>Unix Shell Programming</em> by Lowell
Jay Arthur (Wiley, 1986. This is the first edition, the fourth came out in
1997).
<sect1>Copyright and Disclaimer
<p>
This document is copyright 1998-1999 by Giles Orr. You are encouraged to
redistribute it. You may not modify this document (see the section on
contacting me: I incorporate most changes recommended by readers). Please
contact me if you're interested in doing a translation.
<p>
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.
<!-- ******************************************************* -->
<sect>Bash and Bash Prompts
<sect1>What is Bash?
<p>
Descended from the Bourne Shell, Bash is a GNU product, the
"<bf>B</bf>ourne <bf>A</bf>gain <bf>SH</bf>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.
<sect1>What Can Tweaking Your Bash Prompt Do For You?
<p>
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.
<sect1>Why Bother?
<p>
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.
<p>
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.
<sect1>The First Step
<p>
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 log out). If you want to make a
change to the prompt permanent, look at the section below <ref id="setps"
name="Setting the PS? Strings Permanently">.
<p>
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:
<tscreen><verb>
[giles@nikola giles]$ SAVE=$PS1
[giles@nikola giles]$
</verb></tscreen>
<p>
The simplest prompt would be a single character, such as:
<tscreen><verb>
[giles@nikola giles]$ PS1=$
$ls
bin mail
$
</verb></tscreen>
<p>
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
<tscreen><verb>
$PS1="$ "
$ ls
bin mail
$
</verb></tscreen>
<p>
which forces a space after the prompt, making it more readable. To restore
your original prompt, just call up the variable you stored:
<tscreen><verb>
$ PS1=$SAVE
[giles@nikola giles]$
</verb></tscreen>
<sect1>Bash Prompt Escape Sequences<label id="bpescapes">
<p>
There are a lot of escape sequences offered by the Bash shell for
insertion in the prompt. From the Bash 2.02 man page:
<tscreen><verb>
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
\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
</verb></tscreen>
<p>
Continuing where we left off:
<tscreen><verb>
[giles@nikola giles]$ PS1="\u@\h \W&gt; "
giles@nikola giles&gt; ls
bin mail
giles@nikola giles&gt;
</verb></tscreen>
<p>
This is similar to the default on most Linux distributions. I wanted a
slightly different appearance, so I changed this to:
<tscreen><verb>
giles@nikola giles&gt; PS1="[\t][\u@\h:\w]\$ "
[21:52:01][giles@nikola:~]$ ls
bin mail
[21:52:15][giles@nikola:~]$
</verb></tscreen>
<sect1>Setting the PS? Strings Permanently<label id="setps">
<p>
Various people and distributions set their PS? strings in different places.
The most common places are /etc/profile, /etc/bashrc,
&tilde;/.bash_profile, and &tilde;/.bashrc . Johan Kullstam (<htmlurl
url="mailto:johan19@idt.net" name="johan19@idt.net">) writes:
<quote>
<p>
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.
<p>
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.
<p>
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.
<p>
therefore it should be stressed that PS1=..blah.. should be in .bashrc
and not .profile.
</quote>
<p>
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.
<!-- ****************************************************** -->
<sect>Bash Programming and Shell Scripts
<sect1>Variables
<p>
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 <em>Learning the Bash Shell</em> 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.
<p>
Variables in Bash are assigned much as they are in any programming
language:
<tscreen><verb>
testvar=5
foo=zen
bar="bash prompt"
</verb></tscreen>
Quotes are only needed in an assignment if a space (or special character,
discussed shortly) is a part of the variable.
<p>
Variables are referenced slightly differently than they are assigned:
<tscreen><verb>
&gt; echo $testvar
5
&gt; echo $foo
zen
&gt; echo ${bar}
bash prompt
&gt; echo $NotAssigned
&gt;
</verb></tscreen>
A variable can be referred to as <bf>$bar</bf> or <bf>${bar}</bf>. The
braces are useful when it is unclear what is being referenced: if I write
<bf>$barley</bf> do I mean <bf>${bar}ley</bf> or <bf>${barley}</bf>? Note
also that referencing a value that hasn't been assigned doesn't generate an
error, instead returning nothing.
<sect1>Quotes and Special Characters
<p>
If you wish to include a special character in a variable, you will have to
quote it differently:
<tscreen><verb>
&gt; newvar=$testvar
&gt; echo $newvar
5
&gt; newvar="$testvar"
&gt; echo $newvar
5
&gt; newvar='$testvar'
&gt; echo $newvar
$testvar
&gt; newvar=\$testvar
&gt; echo $newvar
$testvar
&gt;
</verb></tscreen>
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 <bf>eval</bf>
to dereference the stored variable name:
<tscreen><verb>
&gt; echo $testvar
5
&gt; echo $newvar
$testvar
&gt; eval echo $newvar
5
&gt;
</verb></tscreen>
Normally, the shell does only one round of substitutions on the expression
it is evaluating: if you say <bf>echo $newvar</bf> the shell will only go
so far as to determine that <bf>$newvar</bf> is equal to the text string
<bf>$testvar</bf>, it won't evaluate what <bf>$testvar</bf> is equal to.
<bf>eval</bf> forces that evaluation.
<sect1>Command Substitution
<p>
In almost all cases in this document, I use the $(&lt;command&gt;)
convention for command substitution: that is,
<tscreen><verb>
$(date +%H%M)
</verb></tscreen>
<p>
means "substitute the output from the <bf>date +%H%M</bf> 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 (<TT>`date +%H%M`</TT>). 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\' ).
<sect1>Non-Printing Characters in Prompts<label id="nonprintingchars">
<p>
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.
<p>
If I want a very simple prompt consisting of a greater-than sign and a
space:
<tscreen><verb>
[giles@nikola giles]$ PS1='&gt; '
&gt;
</verb></tscreen>
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):
<tscreen><verb>
&gt; PS1='\033[1;33m&gt;\033[0m '
&gt;
</verb></tscreen>
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.
<p>
So use this instead:
<tscreen><verb>
&gt; PS1='\[\033[1;33m\]&gt;\[\033[0m\] '
</verb></tscreen>
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.
<sect1>Sourcing a File
<p>
When a file is sourced (by typing either <bf>source filename</bf> or <bf>.
filename</bf> 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.
<p>
In examples, you will find that I often include <bf>#!/bin/bash</bf> at the
beginning of files including functions. This is <bf>not</bf> necessary if
you are sourcing a file, just as it isn't necessary to <bf>chmod +x</bf> 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.
<sect1>Functions, Aliases, and the Environment
<p>
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:
<p>
"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."
<p>
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.
<p>
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."
<p>
Aliases are simple to create:
<tscreen><verb>
alias d="ls --color=tty --classify"
alias v="d --format=long"
alias rm="rm -i"
</verb></tscreen>
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.)
<p>
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.
<p>
To modify the behaviour of <bf>ls</bf>, you could do something like the
following:
<tscreen><verb>
function lf
{
ls --color=tty --classify $*
echo "$(ls -l $* | wc -l) files"
}
</verb></tscreen>
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.
<!-- *********************************************************** -->
<sect>External Commands
<sect1>PROMPT_COMMAND
<p>
Bash provides another environment variable called <bf>PROMPT_COMMAND</bf>.
The contents of this variable are executed as a regular Bash command
just before Bash displays a prompt.
<tscreen><verb>
[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:~]
</verb></tscreen>
<p>
What happened above was that I changed PS1 to no longer include the
<TT>\t</TT> escape sequence, so the time was no longer a part of the
prompt. Then I used <TT>date +%H%M</TT> to display the time in a format
I like better. But it appears on a different line than the prompt.
Tidying this up using <TT>echo -n ...</TT> 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.
<tscreen><verb>
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:~]
</verb></tscreen>
<p>
<TT>echo -n ...</TT> controls the output of the <TT>date</TT> command and
supresses the trailing newline, allowing the prompt to appear all on one
line. At the end, I used the <TT>unset</TT> command to remove the
PROMPT_COMMAND environment variable.
<sect1>External Commands in the Prompt
<p>
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 <bf>fast</bf> 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.)
<tscreen><verb>
[21:58:33][giles@nikola:~]$ PS1="[\$(date +%H%M)][\u@\h:\w]\$ "
[2159][giles@nikola:~]$ ls
bin mail
[2200][giles@nikola:~]$
</verb></tscreen>
<p>
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.
<p>
Linux comes with a lot of small utility programs like <bf>date</bf>,
<bf>grep</bf>, or <bf>wc</bf> 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.
<p>
An example of a small shell script used within a prompt is given below:
<code>
#!/bin/bash
# lsbytesum - sum the number of bytes in a directory listing
TotalBytes=0
for Bytes in $(ls -l | grep "^-" | cut -c30-41)
do
let TotalBytes=$TotalBytes+$Bytes
done
TotalMeg=$(echo -e "scale=3 \n$TotalBytes/1048576 \nquit" | bc)
echo -n "$TotalMeg"
</code>
<p>
I have at times kept this both as a function, or as a shell script in my
&tilde;/bin directory, which is on my path. Used in a prompt:
<tscreen><verb>
[2158][giles@nikola:~]$ PS1="[\u@\h:\w (\$(lsbytesum) Mb)]\$ "
[giles@nikola:~ (0 Mb)]$ cd /bin
[giles@nikola:/bin (4.498 Mb)]$
</verb></tscreen>
<sect1>What to Put in Your Prompt
<p>
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 are examples from people I know to help give you ideas.
<p>
Dan's prompt is minimal but very effective, particularly for the way he
works.
<tscreen><verb>
[giles@nikola:~]$ cur_tty=$(tty | sed -e "s/.*tty\(.*\)/\1/")
[giles@nikola:~]$ echo $cur_tty
p4
[giles@nikola:~]$ PS1="\!,$cur_tty,\$?\$ "
1095,p4,0$
</verb></tscreen>
<p>
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
weened on Bash do not do), so the first item in the prompt is the history
number. The second item is the significant characters of the tty (the
output of "tty" is cropped with sed), 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 could 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.
<p>Torben Fjerdingstad (tfj@fjerdingstad.dk) wrote to tell me that he often
suspends jobs and then forgets about them. He uses his prompt to remind
himself of suspended jobs:
<tscreen><verb>
[giles@nikola:~]$ function jobcount {
&gt; jobs|wc -l| awk '{print $1}'
&gt; }
[giles@nikola:~]$ export PS1='\W[`jobcount`]# '
giles[0]# man ls &
[1] 4150
[1]+ Stopped (tty output) man ls
giles[1]#
</verb></tscreen>
<p>
Torben uses <bf>awk</bf> to trim the whitespace from the output of wc,
while I would have used sed or tr - not because they're better, but because
I'm more familiar with them. There are probably other ways as well.
Torben also surrounds his PS1 string in single quotes, which prevent Bash
from immediately interpreting the backquotes, so he doesn't have to escape
them as I have mentioned.
<p>
<bf>NOTE:</bf> There is a known bug in Bash 2.02 that causes the
<bf>jobs</bf> 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 suspended. This problem is
fixed in 2.03.
<!-- ********************************************************* -->
<sect>Xterm Title Bar Manipulations<label id="xterm-title-bar">
<p>
Non-printing escape sequences can be used to produce interesting
effects in prompts. To use these escape sequences, you need to enclose
them in <bf>\[</bf> and <bf>\]</bf> (as discussed in <ref
id="nonprintingchars" name="Non-Printing Characters in Prompts">),
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 <bf>\033[</bf> in Bash prior
to version 2, or by either <bf>\033[</bf> or <bf>\e[</bf> in later versions.
<p>
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.
<code>
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='&gt; '
PS4='+ '
}
</code>
<p>
This is a function that can be incorporated into &tilde;/.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
<TT>unset proml</TT>. 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.
<p>
I define this as a function because this is how the Bashprompt package
(discussed later in this document: <ref id="bppackage" name="The Bash
Prompt Package">) deals with prompts: it's not the only way to do it, but
it works well. 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. In this case, to test this at the
prompt, save the above as a text file called "proml". You can work with it
as follows:
<tscreen><verb>
[giles@nikola:/bin (4.498 Mb)]$ cd -> Go where you want to save the prompt
[giles@nikola:~ (0 Mb)]$ vi proml -> Edit the prompt file
... -> Enter the text given above
[giles@nikola:~ (0 Mb)]$ source proml -> Read the prompt function
[giles@nikola:~ (0 Mb)]$ proml -> Execute the prompt function
</verb></tscreen>
<p>
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
<bf>\u@\h:\w</bf>, which puts &lt;user&gt;@&lt;machine&gt;:&lt;working
directory&gt; 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.
<p>
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.
<!-- ******************************************************* -->
<sect>ANSI Escape Sequences: Colours and Cursor Movement
<sect1>Colours
<p>
As mentioned before, non-printing escape sequences have to be enclosed in
<bf>\[\033[</bf> and <bf>\]</bf>. For colour escape sequences, they should
also be followed by a lowercase <bf>m</bf>.
<p>
If you try out the following prompts in an xterm and find that you aren't
seeing the colours named, check out your &tilde;/.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.
<p>
To include blue text in the prompt:
<tscreen><verb>
PS1="\[\033[34m\][\$(date +%H%M)][\u@\h:\w]$ "
</verb></tscreen>
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 <bf>bold</bf> code
might help:
<tscreen><verb>
PS1="\[\033[1;34m\][\$(date +%H%M)][\u@\h:\w]$\[\033[0m\] "
</verb></tscreen>
<p>
The prompt is now in light blue, and it ends by switching the colour
back to nothing (whatever foreground colour you had previously).
<p>
Here are the rest of the colour equivalences:
<tscreen><verb>
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
</verb></tscreen>
<p>
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 <bf>1;31</bf> isn't "Light Red," but "Bold Red." This is true of
all the colours.
<p>
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:
<bf>\[\033[44;1;31m\]</bf>, although setting the colours separately seems
to work better (ie. <bf>\[\033[44m\]\[\033[1;31m\]</bf>). Other codes
available include 4: Underscore, 5: Blink, 7: Inverse, and 8: Concealed.
<p>
<bf>Aside:</bf> Many people (myself included) object strongly to the
"blink" attribute. Fortunately, it doesn't work in any terminal emulators
that I'm aware of - but it will still work on the console. And, 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.
<p>
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:
<code>
function elite
{
local GRAY="\[\033[1;30m\]"
local LIGHT_GRAY="\[\033[0;37m\]"
local CYAN="\[\033[0;36m\]"
local LIGHT_CYAN="\[\033[1;36m\]"
case $TERM in
xterm*)
local TITLEBAR='\[\033]0;\u@\h:\w\007\]'
;;
*)
local TITLEBAR=""
;;
esac
local GRAD1=$(tty|cut -d/ -f3)
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-$LIGHT_GRAY "
}
</code>
<p>
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:
<tscreen><verb>
--(giles@nikola)-(75/ttyp7)-(1908/12-Oct-98)--
--($:~/tmp)--
</verb></tscreen>
<p>
To help myself remember what colours are available, I wrote the following
script which echoes all the colours to screen:
<code>
#!/bin/bash
#
# This file echoes a bunch of colour codes to the terminal to demonstrate
# what's available. Each line is one colour on black and gray
# backgrounds, with the code in the middle. Verified to work on white,
# black, and green BGs (2 Dec 98).
#
echo " On Light Gray: On Black:"
echo -e "\033[47m\033[1;37m White \033[0m\
1;37m \
\033[40m\033[1;37m White \033[0m"
echo -e "\033[47m\033[37m Light Gray \033[0m\
37m \
\033[40m\033[37m Light Gray \033[0m"
echo -e "\033[47m\033[1;30m Gray \033[0m\
1;30m \
\033[40m\033[1;30m Gray \033[0m"
echo -e "\033[47m\033[30m Black \033[0m\
30m \
\033[40m\033[30m Black \033[0m"
echo -e "\033[47m\033[31m Red \033[0m\
31m \
\033[40m\033[31m Red \033[0m"
echo -e "\033[47m\033[1;31m Light Red \033[0m\
1;31m \
\033[40m\033[1;31m Light Red \033[0m"
echo -e "\033[47m\033[32m Green \033[0m\
32m \
\033[40m\033[32m Green \033[0m"
echo -e "\033[47m\033[1;32m Light Green \033[0m\
1;32m \
\033[40m\033[1;32m Light Green \033[0m"
echo -e "\033[47m\033[33m Brown \033[0m\
33m \
\033[40m\033[33m Brown \033[0m"
echo -e "\033[47m\033[1;33m Yellow \033[0m\
1;33m \
\033[40m\033[1;33m Yellow \033[0m"
echo -e "\033[47m\033[34m Blue \033[0m\
34m \
\033[40m\033[34m Blue \033[0m"
echo -e "\033[47m\033[1;34m Light Blue \033[0m\
1;34m \
\033[40m\033[1;34m Light Blue \033[0m"
echo -e "\033[47m\033[35m Purple \033[0m\
35m \
\033[40m\033[35m Purple \033[0m"
echo -e "\033[47m\033[1;35m Pink \033[0m\
1;35m \
\033[40m\033[1;35m Pink \033[0m"
echo -e "\033[47m\033[36m Cyan \033[0m\
36m \
\033[40m\033[36m Cyan \033[0m"
echo -e "\033[47m\033[1;36m Light Cyan \033[0m\
1;36m \
\033[40m\033[1;36m Light Cyan \033[0m"
</code>
<sect1>Cursor Movement
<p>
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:
<tscreen><verb>
- Position the Cursor:
\033[&lt;L&gt;;&lt;C&gt;H
Or
\033[&lt;L&gt;;&lt;C&gt;f
puts the cursor at line L and column C.
- Move the cursor up N lines:
\033[&lt;N&gt;A
- Move the cursor down N lines:
\033[&lt;N&gt;B
- Move the cursor forward N columns:
\033[&lt;N&gt;C
- Move the cursor backward N columns:
\033[&lt;N&gt;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
</verb></tscreen>
<p>
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.
<p>
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): <tt>echo -en "\033[7A\033[1;35m BASH \033[7B\033[6D"</tt>
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.
<p>
Save this in a file called "clock":
<code>
#!/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='+ '
}
</code>
<p>
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.
<p>See also <ref id="clock3" name="The Elegant Useless Clock Prompt"> for a
more extensive use of these codes.
<sect1>Moving the Cursor With tput
<p>
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, or get back information about the status of the
terminal. "tput" for cursor positioning is less flexible than ANSI escape
sequences: you can only move the cursor to an absolute position, you can't
move it relative to its current position. I don't use "tput," so I'm not
going to explain it in detail. Type "man tput" and you'll know as much as
I do.
<!-- ******************************************************** -->
<sect>Special Characters: Octal Escape Sequences
<p>
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 utilise 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 (which many of
us became familiar with with Word Perfect) that are used heavily by the
Bashprompt project are between octal 260 and 337.
<code>
#!/bin/bash
# Script: escgen
function usage {
echo -e "\033[1;34mescgen\033[0m &lt;lower_octal_value&gt; [&lt;higher_octal_value&gt;]"
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
</code>
<p>
You can also use <bf>xfd</bf> to display all the characters in an X font,
with the command "xfd -fn &lt;fontname&gt;". 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.
<!-- ******************************************************** -->
<sect>The Bash Prompt Package<label id="bppackage">
<sect1>Availability
<p>
The Bash Prompt package is available at <htmlurl
url="http://bash.current.nu" name="http://bash.current.nu">, and is the
work of several people, co-ordinated by Rob Current (aka BadLandZ). The
package is an early 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 &tilde;/.bash_profile and
&tilde;/.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).
<sect1>Xterm Fonts
<p>
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:
<quote>
<p>
I love computer history so here goes:
<p>
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).
<p>
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.
<p>
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.
</quote>
<sect1>Changing the Xterm Font
<p>
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 and Slackware 3.4, it may be different on other distributions). "cd"
to that directory, and run the "mkfontdir" command. Then run "xset fp
rehash". 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.
<p>
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:
<tscreen><verb>
xterm -font &lt;fontname&gt;
</verb></tscreen>
<bf>OR</bf>
<tscreen><verb>
xterm -fn &lt;fontname&gt; -fb &lt;fontname-bold&gt;
Eterm -F &lt;fontname&gt;
rxvt -fn &lt;fontname&gt;
</verb></tscreen>
<p>
VGA fonts are available from <em>Stumpy's ANSI Fonts</em> page at <htmlurl
url="http://home.earthlink.net/~us5zahns/enl/ansifont.html"
name="http://home.earthlink.net/~us5zahns/enl/ansifont.html"> (which I have
borrowed from extensively while writing this).
<!-- *************************************************** -->
<sect>Loading a Different Prompt
<sect1>Loading a Different Prompt, Later
<p>
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 &tilde;/.bashrc or as a theme by the bashprompt
package.
<p>
Using the bashprompt package, you would type <TT>bashprompt -i</TT> 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 <TT>bashprompt -l themename</TT>.
bashprompt then modifies your &tilde;/.bash_profile to call the requested
theme when it starts. To set the prompt in future subshells (usually
Xterms, rxvt, etc.), you type <TT>bashprompt -s themename</TT>, and
bashprompt modifies your &tilde;/.bashrc file to call the appropriate theme
at startup.
<p>
See also <ref id="setps" name="Setting the PS? Strings Permanently"> for
Johan Kullstam's note regarding the importance of putting the PS?
strings in &tilde;/.bashrc .
<sect1>Loading a Different Prompt, Immediately
<p>
You can change the prompt in your current terminal (using the example
"elite" function above) by typing "<TT>source elite</TT>" followed by
"<TT>elite</TT>" (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 "<TT>unset elite</TT>" 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 <bf>can</bf> 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.
<!-- ***************************************************** -->
<sect>Loading Prompt Colours Dynamically
<sect1>A "Proof of Concept" Example
<p>
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).
<code>
#!/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]$ "
}
</code>
<p>
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 <TT>source hostloadcolour</TT> and then <TT>hostloadcolour</TT>.
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.
<!-- ******************************************************** -->
<sect>Prompt Code Snippets
<p>
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 will 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.
<p>
To incorporate shell code in prompts, it has to be escaped. Usually, this
will mean putting it inside <tt>\$(&lt;command&gt;)</tt> so that the output
of <tt>command</tt> is substituted each time the prompt is generated.
<sect1>Built-in Escape Sequences
<p>
See <ref id="bpescapes" name="Bash Prompt Escape Sequences"> 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.
<sect1>Date and Time
<p>
If you don't like the built-ins for date and time, extracting the same
information from the <tt>date</tt> command is relatively easy. Examples
already seen in this HOWTO include <tt>date +%H%M</tt>, which will put
in the hour in 24 hour format, and the minute. <tt>date "+%A, %d %B
%Y"</tt> will give something like "Sunday, 06 June 1999". For a full list
of the interpreted sequences, type <tt>date --help</tt> or <tt>man
date</tt>.
<sect1>Counting Files in the Current Directory
<p>
To determine how many files there are in the current directory, put in
<tt>ls -l | wc -l</tt>. This uses <tt>wc</tt> wordcount to do a count of
the number of lines (-l) in the output of <tt>ls -l</tt>. It doesn't count
dotfiles. If you want to count only files and NOT include symbolic links
(just an example of what else you could do), you could use <tt>ls -l | grep
-v ^l | wc -l</tt>. Here, <tt>grep</tt> checks for any line beginning with
"l" (indicating a link), and discards that line (-v).
<sect1>Total Bytes in the Current Directory
<p>
If you want to know how much space the contents of the current directory
take up, you can use something like the following:
<code>
# The sed command replaces all the spaces with only one space.
# cut -d" " -f5 : -d determines a delimiter, which means that (in
# this case) a space begins a new column.
# -f says to take out a certain column, in this case the fifth one
let TotalBytes=0
for Bytes in $(ls -l | grep "^-" | sed -e "s/ \+/ /g" | cut -d" " -f5)
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)
else if [ $TotalBytes -lt 1048576 ]; then
TotalSize=$(echo -e "scale=3 \n$TotalBytes/1024 \nquit" | bc)
else if [ $TotalBytes -lt 1073741824 ]; then
TotalSize=$(echo -e "scale=3 \n$TotalBytes/1048576 \nquit" | bc)
else
TotalSize=$(echo -e "scale=3 \n$TotalBytes/1073741824 \nquit" | bc)
fi
fi
fi
</code>
Code courtesy of Sam Schmit (id@pt.lu) and his uncle Jean-Paul, who ironed
out a fairly major bug in my original code, and just generally cleaned it
up.
<sect1>Checking the Current TTY
<p>
The <tt>tty</tt> 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 have taken to using a more
general solution to this: <tt>tty | sed -e "s:/dev/::"</tt>, 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 <tt>tty | sed -e "s/.*tty\(.*\)/\1/"</tt>.
<p>
An alternative method: <tt>ps aux | grep $$ | awk '{ print $7 }'</tt>.
<sect1>Suspended Job Count
<p>
To find out how many suspended jobs you have, use <tt>jobs | wc -l | awk
'{print $1}'</tt>. <tt>awk</tt> is used to trim the output, which would
otherwise include blank spaces that waste space in a prompt. If you start
netscape from an xterm, this will also be counted. If you want to avoid
that, and only count stopped jobs, use <tt>jobs -s</tt> instead. Type
<tt>help jobs</tt> for more info on jobs. <tt>jobs</tt> will always return
nothing to a pipe in version 2.02 of Bash: this problem is not present in
any other version.
<sect1>Uptime and Load
<p>
Current load is taken from the <tt>uptime</tt> command. What I use at the
moment is <tt>uptime | sed -e "s/.*load average: \(.*\...\), .*\...,
.*\.../\1/" -e "s/ //g"</tt> which is clunky in the extreme, but works.
Replacements welcome. <tt>uptime</tt> can also be used in a very similar
manner to find out how long the machine has been up (obviously) or how many
users are logged in, and the data could be massaged with <tt>sed</tt> to
look the way you want it to.
<sect1>Number of Processes
<p>
<tt>ps ax | wc -l | tr -d " "</tt> <em>OR</em> <tt>ps ax | wc -l | awk
'{print $1}'</tt> <em>OR</em> <tt>ps ax | wc -l | sed -e "s: ::g"</tt>. In
each case, <tt>tr</tt> or <tt>awk</tt> or <tt>sed</tt> is used to remove
the undesirable whitespace.
<sect1>Controlling the Width of $PWD
<p>
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.
<code>
# How many characters of the $PWD should be kept
local pwd_length=30
if [ $(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
</code>
<p>
The above code can be executed as part of PROMPT_COMMAND, and the
environment variable generated (<em>newPWD</em>) can then be included in
the prompt.
<sect1>Laptop Power
<p>
Again, this isn't elegant, but it works (most of the time). If you have a
laptop with APM installed, try <tt>power=$(apm | sed -e "s/.*:
\([1-9][0-9]*\)%/\1/" | tr -d " ")</tt> executed from PROMPT_COMMAND to
create an environment variable you can add to your prompt. This will
indicate percentage power remaining.
<sect1>Having the Prompt Ignored on Cut and Paste
<p>
This one is weird but cool. Rory Toma (rory@corp.webtv.net) wrote to
suggest a prompt like this: <tt>: rory@demon ;</tt> . How is this useful?
Well, if you type a command after the prompt (odd idea, that), you can
triple click on that line (in Linux, anyway) to highlight the whole line,
then paste that line in front of another prompt, and the stuff between the
":" and the "&quot;" is ignored, like so:
<code>
: 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
</code>
The prompt is a no-op, and if your PS2 is set to a space, multiple lines
can be cut and pasted as well.
<sect1>Setting the Window Title and Icon Title Separately<label
id="title-icon-bar">
<p>
A suggestion from Charles Lepple (clepple@negativezero.org) on setting the
window title of the Xterm and the title of the corresponding icon
separately (first check out the earlier section <ref id="xterm-title-bar"
name="Xterm Title Bar Manipulations">). 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.
<!--
**********************************
* *
* Examples Start Here *
* *
**********************************
-->
<sect>Example Prompts
<sect1>Examples on the Web
Over time, many people have e-mailed me excellent examples, and I've
written some interesting ones myself. There are far too many to include
here, so I have put all of the examples together into some web pages which
can be seen at
<htmlurl url="http://www.interlog.com/~giles/bashprompt/prompts/"
name="http://www.interlog.com/~giles/bashprompt/prompts">. Web pages also
allow me to include pictures, which I can't include in a standard HOWTO.
All of the examples given here except Bradley Alexander's "Prompts
Depending on Connection Types" can also be seen on the web.
<sect1>A "Lightweight" Prompt
<p>
<code>
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*)
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='+ '
}
</code>
<sect1>Elite from Bashprompt Themes
<p>
Note that this requires a VGA font.
<code>
# 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="> "
}
</code>
<sect1>A "Power User" Prompt
<p>
I actually do use this prompt, 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 ... Look at it for ideas,
rather than as a practical prompt.
<p>
<code>
#!/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 "^-" | cut -c30-41)
do
let TotalBytes=$TotalBytes+$Bytes
done
TotalMeg=$(echo -e "scale=3 \nx=$TotalBytes/1048576\n if (x&lt;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='+ '
}
</code>
<sect1>Prompt Depending on Connection Type
<p>
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:
<code>
# /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
</code>
<sect1>A Prompt the Width of Your Term
<p>
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.
<code>
#!/bin/bash
# termwide prompt
# by Giles - created 2 November 98
#
# The idea here is to have the upper line of this two line prompt
# always be the width of your term. Do this by calculating the
# width of the text elements, and putting in fill as appropriate
# or left-truncating $PWD.
#
function prompt_command {
TERMWIDTH=${COLUMNS}
# Calculate the width of the prompt:
hostnam=$(echo -n $HOSTNAME | sed -e "s/[\.].*//")
# "whoami" and "pwd" include a trailing newline
usernam=$(whoami)
let usersize=$(echo -n $usernam | wc -c | tr -d " ")
newPWD="${PWD}"
let pwdsize=$(echo -n ${newPWD} | wc -c | tr -d " ")
# Add all the accessories below ...
let promptsize=$(echo -n "--(${usernam}@${hostnam})---(${PWD})--" \
| wc -c | tr -d " ")
let fillsize=${TERMWIDTH}-${promptsize}
fill=""
while [ "$fillsize" -gt "0" ]
do
fill="${fill}-"
let fillsize=${fillsize}-1
done
if [ "$fillsize" -lt "0" ]
then
let cut=3-${fillsize}
newPWD="...$(echo -n $PWD | sed -e "s/\(^.\{$cut\}\)\(.*\)/\2/")"
fi
}
PROMPT_COMMAND=prompt_command
function termwide {
local GRAY="\[\033[1;30m\]"
local LIGHT_GRAY="\[\033[0;37m\]"
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*)
TITLEBAR='\[\033]0;\u@\h:\w\007\]'
;;
*)
TITLEBAR=""
;;
esac
PS1="$TITLEBAR\
$YELLOW-$LIGHT_BLUE-(\
$YELLOW\${usernam}$LIGHT_BLUE@$YELLOW\${hostnam}\
${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 "
}
</code>
<sect1>The Elegant Useless Clock Prompt<label id="clock3">
<p>
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.
<p>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.
<code>
#!/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}<7D>"
# 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 "
}
</code>
</article>