How to change the title of an xterm

Richard Lister, ric@giccs.georgetown.edu

$Revision: 1.6 $, Last modified: Wed Jan 7 14:34:31 EST 1998


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.

Where to find this document

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

The latest version can always be found at http://www.giccs.georgetown.edu/~ric/howto/Xterm-Title.html.


Static titles

A static title may be set for any of the terminals xterm, color-xterm or rxvt, by using the -T and -n switches:

  xterm -T "My XTerm's Title" -n "My XTerm's Icon Title"

Dynamic titles

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.

This may be done by using XTerm escape sequences. The following sequences are useful in this respect:

  ESC]0;stringBEL    Set icon name and window title to string
  ESC]1;stringBEL    Set icon name to string
  ESC]2;stringBEL    Set window title to string
where ESC is the escape character (\033), and BEL is the bell character (\007).

Note: these sequences apply to most xterm derivatives, such as nxterm, color-xterm and rxvt. Other terminal types often use different escapes; see the appendix for examples. For the full list of xterm escape sequences see the file ctlseq2.txt, which comes with the xterm distribution, or xterm.seq, which comes with the rxvt distribution.

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.


Examples for different shells

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

zsh

zsh provides some functions and expansions, which we will use:

  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 '~'
There are many more expansions available: see 'man zshmisc'.

Thus, the following inserted in ~/.zshrc will set the xterm title to "username@hostname: directory" ...

  case $TERM in
      xterm*)
          precmd () {print -Pn "\e]0;%n@%m: %~\a"}
          ;;
  esac
This could also be achieved by using chpwd() instead of precmd().

bash

bash supplies a variable PROMPT_COMMAND which contains a command to execute before the prompt. This example (inserted in ~/.bashrc) sets the title to "username@hostname: directory":

  PROMPT_COMMAND='echo -ne "\033]0;${USER}@${HOSTNAME}: ${PWD}\007"'
where \033 is the character code for ESC, and \007 for BEL. Note that the quoting is important here: variables are expanded in "...", and not expanded in '...'. So PROMPT_COMMAND is set to an unexpanded value, but the variables inside "..." are expanded when PROMPT_COMMAND is used.

However, PWD produces the full directory path. If we want to use the '~' 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:

  \u          expands to $USERNAME
  \h          expands to hostname up to first '.'
  \w          expands to directory, replacing $HOME with '~'
  \[...\]     embeds a sequence of non-printing characters

Thus, the following produces a prompt of "bash$ ", and an xterm title of "username@hostname: directory" ...

  case $TERM in
      xterm*)
          PS1="\[\033]0;\u@\h: \w\007\]bash\$ "
          ;;
      *)
          PS1="bash\$ "
          ;;
  esac
Note the use of \[...\], which tells bash to ignore the non-printing control characters when calculating the width of the prompt. Otherwise line editing commands get confused while placing the cursor.

tcsh

tcsh has functions and expansions similar to those of zsh:

  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 '~'

Unfortunately, there is no equivalent to zsh's print command allowing us to use prompt escapes in the title string, so the best we can do is to use shell variables (in ~/.tcshrc):

  switch ($TERM)
      case "xterm*":
          alias precmd 'echo -n "\033]0;${HOST}:$cwd\007"'
          breaksw
  endsw
but this gives the directory's full path instead of using '~'. Instead you can insert the string in the prompt:
  switch ($TERM)
      case "xterm*":
          set prompt="%{\033]0;%n@%m:%~\007%}tcsh%% "
          breaksw
      default:
          set prompt="tcsh%% "
          breaksw
  endsw
which sets a prompt of "tcsh% ", and an xterm title and icon of "username@hostname: directory". Note that the "%{...%}" must be placed around escape sequences (and cannot be the last item in the prompt: see 'man tcsh' for the details).

csh

This is very difficult indeed in csh, and we end up doing something like the following (in ~/.cshrc):

  switch ($TERM)
      case "xterm*":
          set host=`hostname`
          set user=`whoami`
          alias cd 'cd \!*; set prompt="^[]0;${user}@${host}: ${cwd}^Gcsh% "'
          breaksw
      default:
          set prompt='csh% '
          breaksw
  endsw
where we have had to alias the cd command to do all the work of setting the prompt. Note that the '^[' and '^G' in the prompt string are single characters for ESC and BEL (can be entered in emacs using 'C-q ESC' and 'C-q C-g').

I strongly recommend abandoning csh in favour of a more advanced shell: zsh, bash or tcsh.

ksh

ksh 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 "username@hostname: directory" and a prompt of "ksh$ ".

  case $TERM in
      xterm*)
          HOST=`hostname`
          PS1='^[]0;${USER}@${HOST}: ${PWD}^Gksh$ '
          ;;
      *)
          PS1='ksh$ '
          ;;
  esac
However, PWD produces the full directory path. We can remove the prefix of $HOME/ from the directory using the ${...##...} construct. We can also use ${...%%...} to truncate the hostname:
  HOST=`hostname`
  HOST=${HOST%%.*}
  PS1='^[]0;${USER}@${HOST}: ${PWD##${HOME}/}^Gksh$ '
Note that the '^[' and '^G' in the prompt string are single characters for ESC and BEL (can be entered in emacs using 'C-q ESC' and 'C-q C-g').


Appendix: escapes for other terminal types

SGI wsh, xwsh and winterm

These terminals set TERM=iris-ansi and use the following escapes:

  ESC P 1 .y string ESC \\        Set window title to string
  ESC P 3 .y string ESC \\        Set icon title to string
For the full list of xwsh escapes see xwsh(1G).

Sun cmdtool and shelltool

cmdtool and shelltool both set TERM=sun-cmd and use the following escapes:

  ESC ] l string ESC \            Set window title to string
  ESC ] L string ESC \            Set icon title to string
These are truly awful programs: use something else.

CDE dtterm

dtterm sets TERM=dtterm, and appears to recognise both the standard xterm escape sequences and the Sun cmdtool sequences. (I've only tested this on a Sun ... anyone have HP and DEC versions they can test for me?).

Example

Here's my full setup using zsh to handle all these terminal types:

  case $TERM in

    xterm*|dtterm)
      precmd () {print -Pn "\e]0;%n@%m: %~\a"}  ## window & icon title
      ;;

    iris-ansi)
      precmd () {
        print -Pn "\eP1.y%n@%m: %~\e\\"         ## window title
        print -Pn "\eP3.y%n@%m: %~\e\\"         ## icon title
      }
      ;;

    sun-cmd)
      precmd () {
        print -Pn "\e]l%n@%m: %~\e\\"           ## window title
        print -Pn "\e]L%n@%m: %~\e\\"           ## icon title
      }
      ;;

  esac

Credits

Thanks to the following people.
Paul D. Smith <psmith@BayNetworks.COM> and Christophe Martin <cmartin@ipnl.in2p3.fr>
both pointed out that I had the quotes the wrong way round in the bash PROMPT_COMMAND. Getting them right means variables are expanded dynamically.
Paul D. Smith <psmith@BayNetworks.COM>
suggested the use of \[...\] in the bash prompt for embedding non-printing characters.
Christophe Martin <cmartin@ipnl.in2p3.fr>
provided the solution for ksh.
Keith Turner <keith@silvaco.com>
supplied the escape sequences for Sun cmdtool and shelltool.