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