<!doctype linuxdoc system>
<!-- $Id$ -->

<article>

<title>How to change the title of an xterm</title>
<author>Ric Lister, <tt>ric@giccs.georgetown.edu</tt></author>
<date>v2.0, 27 October 1999</date>

<abstract>
This document explains how to use escape sequences to
dynamically change window and icon titles of an xterm. Examples are
given for several shells, and the appendix gives escape sequences
for some other terminal types.
</abstract>


<toc>


<sect>Where to find this document

<p>
This document is now part of the
<url name="Linux HOWTO Index" url="http://sunsite.unc.edu/LDP/HOWTO/">
and can be found at 
<url url="http://sunsite.unc.edu/LDP/HOWTO/mini/Xterm-Title.html">.

<p>
The latest version can always be found in several formats at 
<url url="http://www.giccs.georgetown.edu/~ric/howto/Xterm-Title/">.

<p>
This document supercedes the original howto written
by Winfried Tr&uuml;mper.


<sect>Static titles

<p>
A static title may be set for any of the terminals <tt>xterm</tt>,
<tt>color-xterm</tt> or <tt>rxvt</tt>, by using the <tt>-T</tt> and
<tt>-n</tt> switches:
<tscreen>
xterm -T "My XTerm's Title" -n "My XTerm's Icon Title"
</tscreen>


<sect>Dynamic titles

<p>
Many people find it useful to set the title of a terminal to reflect
dynamic information, such as the name of the host the user is logged
into, the current working directory, etc.


<sect1>xterm escape sequences

<p>
Window and icon titles may be changed in a running xterm
by using XTerm escape sequences. The following sequences
are useful in this respect:
<itemize>
  <item><tt>ESC]0;<bf>string</bf>BEL</tt> -- Set icon name and window title
        to <bf>string</bf>
  <item><tt>ESC]1;<bf>string</bf>BEL</tt> -- Set icon name to <bf>string</bf>
  <item><tt>ESC]2;<bf>string</bf>BEL</tt> -- Set window title to
        <bf>string</bf>
</itemize>
where <tt>ESC</tt> is the <bf>escape</bf> character (\033), and <tt>BEL</tt> is
the <bf>bell</bf> character (\007).

<p>
Printing one of these sequences within the xterm will cause the
window or icon title to be changed. 

<p>
<bf>Note</bf>: these sequences apply to most xterm derivatives,
such as <tt>nxterm</tt>, <tt>color-xterm</tt> and <tt>rxvt</tt>. Other
terminal types often use different escapes; see the
appendix for examples. For the full list of 
xterm escape sequences see the file 
<url name="ctlseq2.txt"
url="http://www.giccs.georgetown.edu/~ric/howto/Xterm-Title/ctlseq2.txt">,
which comes with the xterm distribution, or
<url url="http://www.giccs.georgetown.edu/~ric/howto/Xterm-Title/xterm.seq"
name="xterm.seq">, which comes with the
<url url="http://www.rxvt.org/" name="rxvt"> distribution.


<sect1>Printing the escape sequences

<p>
For information that is constant throughout the lifetime of
this shell, such as host and username, it will suffice to
simply echo the escape string in the shell rc file:
<tscreen><verb>
echo -n "\033]0;${USER}@${HOST}\007"
</verb></tscreen>
should produce a title like <tt>username@hostname</tt>, assuming
the shell variables <tt>$USER</tt> and <tt>$HOST</tt> are set correctly.
The required options for <tt>echo</tt> may vary by shell (see examples
below).

<p>
For information that may change during the shell's lifetime, such
as current working directory, these escapes really need to be
applied every time the prompt changes. 
This way the string is updated with every command you issue and can keep
track of information such as current working directory, username, hostname,
etc. Some shells provide special functions for this purpose, some don't
and we have to insert the title sequences directly into the prompt
string. This is illustrated in the next section.


<sect>Examples for different shells

<p>
Below we provide an set of examples for some of the more common shells.
We start with <tt>zsh</tt> as it provides several facilities that
make our job much easier. We will then progress through increasingly
difficult examples.

<p>
In all the examples we test the environment variable <tt>$TERM</tt>
to make sure we only apply the escapes to xterms. We test for
<tt>$TERM=xterm*</tt>; the wildcard is because some variants (such as
rxvt) can set <tt>$TERM=xterm-color</tt>.

<p>
We should make an extra comment about C shell derivatives, such as
<tt>tcsh</tt> and <tt>csh</tt>. In C shells, undefined variables are
fatal errors. Therefore, before testing the variable <tt>$TERM</tt>, it
is necessary to test for its existence so as not to break non-interactive
shells. To achieve this you must wrap the examples below in something
like:
<tscreen><verb>
  if ($?TERM) then
      ...
  endif
</verb></tscreen>
(In our opinion this is just one of many reasons not to use C shells. See
<it><url name="Csh Programming Considered Harmful"
url="http://language.perl.com/versus/csh.whynot"></it> for a useful
discussion).

<p>
The examples below should be used by inserting them into the appropriate
shell initialisation file; i.e. one that is sourced by interactive shells
on startup. In most cases this is called something like
<tt>.<it>shell</it>rc</tt> (e.g. <tt>.zshrc</tt>, <tt>.tcshrc</tt>, etc).



<sect1>zsh

<p>
<tt>zsh</tt> provides some functions and expansions, which we will use:
<tscreen><verb>
precmd ()   a function which is executed just before each prompt
chpwd ()    a function which is executed whenever the directory is changed
\e          escape sequence for escape (ESC)
\a          escape sequence for bell (BEL)
%n          expands to $USERNAME
%m          expands to hostname up to first '.'
%~          expands to directory, replacing $HOME with '~'
</verb></tscreen>
There are many more expansions available: see the <tt>zshmisc</tt> man page.

<p>
Thus, the following will set the xterm title to
"<tt><it>username</it>@<it>hostname</it>: <it>directory</it></tt>":
<tscreen><verb>
case $TERM in
    xterm*)
        precmd () {print -Pn "\e]0;%n@%m: %~\a"}
        ;;
esac
</verb></tscreen>
This could also be achieved by using <tt>chpwd()</tt> instead
of <tt>precmd()</tt>. The <tt>print</tt> builtin works like
<tt>echo</tt>, but gives us access to the <tt>%</tt> prompt escapes.


<sect1>tcsh

<p>
<tt>tcsh</tt> has some functions and expansions similar to those of
<tt>zsh</tt>:
<tscreen><verb>
precmd ()   a function which is executed just before each prompt
cwdcmd ()   a function which is executed whenever the directory is changed
%n          expands to username
%m          expands to hostname
%~          expands to directory, replacing $HOME with '~'
%#	    expands to '>' for normal users, '#' for root users
%{...%}     includes a string as a literal escape sequence
</verb></tscreen>

<p>
Unfortunately, there is no equivalent to <tt>zsh</tt>'s <tt>print</tt>
command allowing us to use prompt escapes in the title string,
so the best we can do is to use shell variables (in <tt>~/.tcshrc</tt>):
<tscreen><verb>
switch ($TERM)
    case "xterm*":
        alias precmd 'echo -n "\033]0;${HOST}:$cwd\007"'
        breaksw
endsw
</verb></tscreen>
However, this gives the directory's full path instead of using <tt>~</tt>.
Instead you can insert the string in the prompt:
<tscreen><verb>
switch ($TERM)
    case "xterm*":
        set prompt="%{\033]0;%n@%m:%~\007%}tcsh%# "
        breaksw
    default:
        set prompt="tcsh%# "
        breaksw
endsw
</verb></tscreen>
which sets a prompt of "<tt>tcsh% </tt>", and an xterm title and icon
of "<tt><it>username</it>@<it>hostname</it>: <it>directory</it></tt>". Note that
the "<tt>%{...%}</tt>" must be placed around escape sequences (and cannot
be the last item in the prompt: see the <tt>tcsh</tt> man page for details).


<sect1>bash

<p>
<tt>bash</tt> supplies a variable <tt>$PROMPT_COMMAND</tt> which contains a
command to execute before the prompt. This example sets the title to
<tt>username@hostname: directory</tt>:
<tscreen><verb>
PROMPT_COMMAND='echo -ne "\033]0;${USER}@${HOSTNAME}: ${PWD}\007"'
</verb></tscreen>
where <tt>\033</tt> is the character code for <tt>ESC</tt>,
and <tt>\007</tt> for <tt>BEL</tt>.

<p>
Note that the quoting is important here: variables are expanded in
<tt>"..."</tt>, and not expanded in <tt>'...'</tt>. So
<tt>$PROMPT_COMMAND</tt> is set to an unexpanded value, but the
variables inside <tt>"..."</tt> are expanded when
<tt>$PROMPT_COMMAND</tt> is used.

<p>
However, <tt>$PWD</tt> produces the full directory path. If we want to
use the <tt>~</tt> shorthand we need to embed the escape string in the
prompt, which allows us to take advantage of the following prompt expansions
provided by the shell:
<tscreen><verb>
\u          expands to $USERNAME
\h          expands to hostname up to first '.'
\w          expands to directory, replacing $HOME with '~'
\$	    expands to '$' for normal users, '#' for root
\[...\]     embeds a sequence of non-printing characters
</verb></tscreen>

<p>
Thus, the following produces a prompt of <tt>bash$ </tt>, and an xterm
title of <tt>username@hostname: directory</tt>:
<tscreen><verb>
case $TERM in
    xterm*)
        PS1="\[\033]0;\u@\h: \w\007\]bash\\$ "
        ;;
    *)
        PS1="bash\\$ "
        ;;
esac
</verb></tscreen>
Note the use of <tt>\[...\]</tt>, which tells <tt>bash</tt> to ignore
the non-printing control characters when calculating the width
of the prompt. Otherwise line editing commands get confused while
placing the cursor.


<sect1>ksh

<p>
<tt>ksh</tt> provides little in the way of functions and expansions, so
we have to insert the escape string in the prompt to have it updated
dynamically. This example produces a title of 
<tt>username@hostname: directory</tt> and a prompt of <tt>ksh$ </tt>.
<tscreen><verb>
case $TERM in
    xterm*)
        HOST=`hostname`
        PS1='^[]0;${USER}@${HOST}: ${PWD}^Gksh$ '
        ;;
    *)
        PS1='ksh$ '
        ;;
esac
</verb></tscreen>
However, <tt>$PWD</tt> produces the full directory path. We can remove the
prefix of <tt>$HOME/</tt> from the directory using the <tt>${...##...}</tt>
construct. We can also use <tt>${...%%...}</tt> to truncate the hostname:
<tscreen><verb>
HOST=`hostname`
HOST=${HOST%%.*}
PS1='^[]0;${USER}@${HOST}: ${PWD##${HOME}/}^Gksh$ '
</verb></tscreen>
Note that the <tt>^[</tt> and <tt>^G</tt> in the prompt string are single
characters for <tt>ESC</tt> and <tt>BEL</tt> (can be entered in emacs
using <tt>C-q ESC</tt> and <tt>C-q C-g</tt>).


<sect1>csh

<p>
This is very difficult indeed in <tt>csh</tt>, and we end up doing something
like the following:
<tscreen><verb>
switch ($TERM)
    case "xterm*":
        set host=`hostname`
        alias cd 'cd \!*; echo -n "^[]0;${user}@${host}: ${cwd}^Gcsh% "'
        breaksw
    default:
        set prompt='csh% '
        breaksw
endsw
</verb></tscreen>
where we have had to alias the <tt>cd</tt> command to do the work of
sending the escape sequence. Note that the <tt>^[</tt> and <tt>^G</tt> in
the string are single characters for <tt>ESC</tt> and <tt>BEL</tt>
(can be entered in emacs using <tt>C-q ESC</tt> and <tt>C-q C-g</tt>).

<p>
Notes: on some systems <tt>hostname -s</tt> may be used to get
a short, rather than fully-qualified, hostname. Some users with
symlinked directories may find <tt>`pwd`</tt> (backquotes to run the
<tt>pwd</tt> command) gives a more accurate path than <tt>$cwd</tt>.



<sect>Printing the current job name

<p>
Often a user will start a long-lived foreground job such as <tt>top</tt>,
an editor, an email client, etc, and wishes the name of the job
to be shown in the title. This is a more thorny problem and is
only achieved easily in <tt>zsh</tt>.

<sect1>zsh

<p>
<tt>zsh</tt> provides an ideal builtin function for this purpose:
<tscreen><verb>
preexec()   a function which is just before a command is executed
$*,$1,...   arguments passed to preexec()
</verb></tscreen>
Thus, we can insert the job name in the title as follows:
<tscreen><verb>
case $TERM in
    xterm*)
      preexec () {
        print -Pn "\e]0;$*\a"
      }
    ;;
esac
</verb></tscreen>
Note: the <tt>preexec()</tt> function appeared around version 3.1.2
of <tt>zsh</tt>, so you may have to upgrade from an earlier version.


<sect1>Other shells

<p>
This is not easy in other shells which lack an equivalent of the
<tt>preexec()</tt> function. If anyone has examples please email
them to the author.


<sect>Appendix: escapes for other terminal types

<p>
Many modern terminals are descended from <tt>xterm</tt> or <tt>rxvt</tt>
and support the escape sequences we have used so far. Some proprietary
terminals shipped with various flavours of unix use their own
escape sequences.


<sect1>IBM <tt>aixterm</tt>

<p>
<tt>aixterm</tt> recognises the <tt>xterm escape</tt> sequences.


<sect1>SGI <tt>wsh</tt>, <tt>xwsh</tt> and <tt>winterm</tt>

<p>
These terminals set <tt>$TERM=iris-ansi</tt> and use the following escapes:
<itemize>
<item><tt>ESCP1.y<it>string</it>ESC\        Set window title to <it>string</it></tt>
<item><tt>ESCP3.y<it>string</it>ESC\        Set icon title to <it>string</it></tt>
</itemize>
For the full list of <tt>xwsh</tt> escapes see the <tt>xwsh(1G)</tt> man page.

<p>
The Irix terminals also support the <tt>xterm</tt> escapes to individually
set window title and icon title, but not the escape to set both.


<sect1>Sun <tt>cmdtool</tt> and <tt>shelltool</tt>

<p>
<tt>cmdtool</tt> and <tt>shelltool</tt> both set <tt>$TERM=sun-cmd</tt> 
and use the following escapes:
<itemize>
<item><tt>ESC]l<it>string</it>ESC\    Set window title to <it>string</it></tt>
<item><tt>ESC]L<it>string</it>ESC\    Set icon title to <it>string</it></tt>
</itemize>
These are truly awful programs: use something else.


<sect1>CDE <tt>dtterm</tt>

<p>
<tt>dtterm</tt> sets <tt>$TERM=dtterm</tt>, and appears to recognise both the
standard <tt>xterm</tt> escape sequences and the Sun <tt>cmdtool</tt>
sequences (tested on Solaris 2.5.1, Digital Unix 4.0, HP-UX 10.20).


<sect1>HPterm

<p>
<tt>hpterm</tt> sets <tt>$TERM=hpterm</tt> and uses the following escapes:
<itemize>
<item><tt>ESC&amp;f0k<it>length</it>D<it>string</it>   Set window title to <it>string</it> of length <it>length</it></tt>
<item><tt>ESC&amp;f-1k<it>length</it>D<it>string</it>  Set icon title to <it>string</it> of length <it>length</it></tt>
</itemize>

<p>
A basic C program to calculate the length and echo the string looks like this:
<tscreen><verb>
#include <string.h>
int main(int argc, char *argv[])
{
    printf("\033&amp;f0k%dD%s", strlen(argv[1]), argv[1]);
    printf("\033&amp;f-1k%dD%s", strlen(argv[1]), argv[1]);
    return(0);
}
</verb></tscreen>

<p>
We may write a similar shell-script, using the <tt>${#string}</tt>
(<tt>zsh</tt>, <tt>bash</tt>, <tt>ksh</tt>) or <tt>${%string}</tt>
(<tt>tcsh)</tt> expansion to find the string length. The following
is for <tt>zsh</tt>:
<tscreen><verb>
case $TERM in
    hpterm)
        str="\e]0;%n@%m: %~\a"
	precmd () {print -Pn "\e&amp;f0k${#str}D${str}"}
   	precmd () {print -Pn "\e&amp;f-1k${#str}D${str}"}
	;;
esac
</verb></tscreen>




<sect>Appendix: examples in other languages

<p>
It may be useful to write a small program to print an argument to
the title using the <tt>xterm</tt> escapes. Some examples are provided
below.


<sect1>C

<p>
<tscreen><verb>
#include <stdio.h>

int main (int argc, char *argv[]) {
  printf("%c]0;%s%c", '\033', argv[1], '\007');
  return(0);
}
</verb></tscreen>


<sect1>Perl

<p>
<tscreen><verb>
#!/usr/bin/perl
print "\033]0;@ARGV\007";
</verb></tscreen>



<sect>Credits

<p>
Thanks to the following people who have provided advice, errata, and
examples for this document.

<p>
Paul D. Smith <tt>&lt;psmith@BayNetworks.COM&gt;</tt> and
Christophe Martin <tt>&lt;cmartin@ipnl.in2p3.fr&gt;</tt>
both pointed out that I had the quotes the wrong way round in the
<tt>bash</tt> <tt>$PROMPT_COMMAND</tt>. Getting them right
means variables <it>are</it> expanded dynamically.

<p>
Paul D. Smith <tt>&lt;psmith@BayNetworks.COM&gt;</tt>
suggested the use of <tt>\[...\]</tt> in the <tt>bash</tt>
prompt for embedding non-printing characters.

<p>
Christophe Martin <tt>&lt;cmartin@ipnl.in2p3.fr&gt;</tt>
provided the solution for <tt>ksh</tt>.

<p>
Keith Turner <tt>&lt;keith@silvaco.com&gt;</tt>
supplied the escape sequences for Sun <tt>cmdtool</tt> and
<tt>shelltool</tt>.

<p>
Jean-Albert Ferrez <tt>&lt;ferrez@dma.epfl.ch&gt;</tt>
pointed out some inconsistencies in the use of "<tt>PWD</tt>"
and "<tt>$PWD</tt>", and in the use of "<tt>\</tt>" vs "<tt>\\</tt>".

<p>
Bob Ellison <tt>&lt;papillo@hpellis.fc.hp.com&gt;</tt> and
Jim Searle <tt>&lt;jims@broadcom.com&gt;</tt> tested <tt>dtterm</tt>
on HP-UX.

<p>
Teng-Fong Seak <tt>&lt;seak@drfc.cad.cea.fr&gt;</tt> suggested the
<tt>-s</tt> option for <tt>hostname</tt>, use of <tt>`pwd`</tt>, and
use of <tt>echo</tt> under <tt>csh</tt>.

<p>
Trilia <tt>&lt;trilia@nmia.com&gt;</tt> suggested examples
in other languages.

<p>
Brian Miller <tt>&lt;bmiller@telstra.com.au&gt;</tt> supplied the
escape sequences and examples for <tt>hpterm</tt>.

<p>
Lenny Mastrototaro <tt>&lt;lenny@click3x.com&gt;</tt> explained
the Irix terminals' use of xterm escape sequences. 

<p>
Paolo Supino <tt>&lt;paolo@init.co.il&gt;</tt> suggested the use
of <tt>\\$</tt> in the <tt>bash</tt> prompt.

</article>
