4.6. Faster Prompt Setting with Built-ins
To
set your prompt, you execute a
command (on most shells, that command sets a shell variable). Before
setting the prompt, you may run other commands to get information for
it: the current directory name, for example. A shell can run two
kinds of commands: built-in and
external (Section 1.9). Built-in commands
usually run faster than external commands. On a slow computer, the
difference may be important -- waiting a few seconds for your
prompt to reset can get irritating (though the computer would have to
be quite slow nowadays for it to matter that much). Creative use of
your shell's built-in commands might pay off there,
and they are still quite useful for those trying to squeeze the most
performance out of their system. Let's look at some
examples:
-
Section 4.3 has examples of some shells'
special characters, such as %D to give the current
date. Check your shell's manual page; if it has
these features, using them won't slow you down the
way an external command in backquotes (Section 28.14),
like 'date', might.
-
If
you're putting your current directory in your
prompt, you may only want the tail of the pathname (the name past the
last slash). How can you edit a pathname? You might think of using
basename (Section 36.13) or sed
(Section 34.1) with the current directory from
$cwd -- as in the first command in the
following code listing, and probably in an alias like setprompt (Section 4.7) to
make sure the prompt is updated whenever you change directories. The
faster way is with the second command, using the C
shell's built-in
"tail" operator,
:t:
set prompt="`basename $cwd`% "
{} Section 35.9
set prompt="${cwd:t}% "
If your current directory is
/usr/users/hanna/projects, either of those
prompts would look like "projects%
" (with a space after the percent sign).
The C shell has several of these
built-in string operators
(Section 28.5) like :t; the Korn Shell,
zsh, and bash have
more-powerful string operators
(Section 28.5).
-
If your prompt gets complex, you can use a shell function (Section 29.11)
to access other built-in commands and edit the prompt. This can be
faster than using an external shell or Perl script because functions
run within the shell instead of in an external process.
Here's an example from my
.zshrc file:
${+} Section 36.7, $(...) Section 28.14
# Change "script" prompt automatically so I remember I'm in one.
alias script='SCRIPT=yes /usr/bin/script'
#
# Functions:
#
setprompt( ) {
case "${TTY##*/}" in
tty[1-9]) xpi=':tty%l' ;; # Virtual console
*) xpi= ;;
esac
PS1="
$USER@%m$xpi $(dirs)
%* \$(folder -list)
${SCRIPT+SCRIPT-}%!%# "
}
Before the
function, I set an alias that temporarily sets an environment
variable named SCRIPT while the script (Section 37.7) program
is running. The setprompt function, running in the
child shell under script, sees that this
environment variable has been set and adds the string
SCRIPT- before the prompt. This reminds me that
I'm logging to a script file. (If this is hard to
visualize, Section 24.3 and Section 35.3 have some background.)
The
setprompt function itself has two parts. The first
is a case statement (Section 35.11) that
tests $TTY, the name of the tty (Section 2.7)
I'm currently using. If the name ends in
tty1, tty2, etc.,
it's one of my Linux virtual
consoles (Section 23.12). In that case, I
want to add the console name (tty1, etc.) to my
prompt -- so I store the name in the xpi
(extra prompt
info) shell variable. This
variable's value -- if it's been
set -- is expanded when the prompt is printed. The second part
sets the prompt variable PS1. The whole prompt
looks like this:
jpeek@kludge:tty1 ~/pt/art
15:38:30 inbox pt
501%
The first line shows my username, hostname, the virtual console name
(if any), and the current directory (in this example, there was
nothing else on the directory stack
(Section 31.7)). The second line has the
time -- and my email folder stack, from the MH folder
-list command, which is the only nonbuilt-in command used
in the prompt. And here's a subtle point
that's worth perusing. The whole
prompt string is inside double quotes (Section 27.12)
so that variable and command substitution will happen whenever
setprompt is run. But, the way my prompt is set,
the MH folder stack may change between the times that
setprompt resets the prompt. So I escape the
$ in \$(folder -list). This
stores the command substitution without executing
folder! So, when every prompt
is about to be printed, the shell will evaulate the prompt string and
expand the $(...) operators into the current
folder stack. The third line sets the end of the prompt string: the
zsh prompt substitution at %m,
%*, %! and
%#.
On a slow machine, I'd try hard to find a way to
eliminate the external folder -list command. But
my Linux box is fast enough so that I don't notice
any delay before a prompt. To make this work, I needed a good
understanding of what's evaluated when.
It's this sort of subtlety that makes prompt setting
a challenge -- and a pleasure, too, when you get it working just
right.
As another example, Section 4.14 shows more
about using dirs in a shell prompt.
--JP and SJC
| | | 4.5. C-Shell Prompt Causes Problems in vi, rsh, etc. | | 4.7. Multiline Shell Prompts |
Copyright © 2003 O'Reilly & Associates. All rights reserved.
|
|