Customizing the Terminal: The Prompt
Written by BinnyVA on March 10, 2009 – 11:34 pm -
Most Linux ‘gurus’ spend a lot of time working in the terminal. If you belong to that group, this post is for you. This is a tutorial to configure the terminal prompt to the best possible value for your use. Note: This tutorial is for bash users – these instructions will not work in other shells.
The Prompt
You must have seen the prompt if you have use the terminal – it is the first few characters in each line. Usually, it will be…
[username@localhost] ~ $
In this case, the user is shown three piece of information in the prompt –
- Username of the current user
- Hostname
- Current folder name
This post will show you how to customize this prompt to your needs.
Editing the Prompt
Editing the prompt is very simple – you just have to edit a shell variable. To see the current prompt’s value, open a shell and type the command…
echo $PS1
The result will be something like this(in Ubuntu)…
binnyva@binlap:~$ echo $PS1
\[\e]0;\u@\h: \w\a\]${debian_chroot:+($debian_chroot)}\u@\h:\w\$
Which is functionally the same as…
\u@\h:\W\$
To edit this variable, run the command…
export PS1=<New Prompt Value>
Most desktop systems don’t need the username and hostname in the prompt – this is only relevent if your are connected to a remote system. So the first thing to do, if you are on a desktop system, is to remove those two. To do that, run the command…
export PS1="[\W]\$ "
This will change the prompt in the current terminal. To make it permanent, edit the ~/.bashrc and set the PS1 variable there. Just add this line at the end of the file…
export PS1="[\W]\$ "
A Better Prompt
Currently, the prompt has the basename of the current working directory. That is, if we are in ‘~/Sites/Lindesk/posts’, the prompt will be ‘[posts]$ ‘. This is good enough for most people. But I have a problem with this. If I go to another folder, say, ‘~/Sites/OpenJS/posts’, the prompt is still ‘[posts]$ ‘. The prompt is a bit ambiguous in this case. This can be done using a different character – in this case \w(small ‘w’ – the default was capital ‘W’).
[posts]$ export PS1="[\w]$ "
[~/Sites/OpenJS/posts]$ _
This is nice – but you will have a problem if the directory you are in is several levels deep. It might be something like this…
[/var/www/html/sites/Lindesk/lindesk.com/wp-content/plugins/eventr/langs]$ _
That’s long – and inconvenient. There are better ways of doing this.
Show the Beginning and the End.
A better way of doing this is to cut of a part of the folder – so the above path will look something like…
[/var/www/html.../eventr/langs] $ _
This option will show the first 15 characters of the path and then the last 15 characters – if the directory path is bigger than 30 characters. To enable this mode, open up the file ~/.bashrc and add this code…
PROMPT_COMMAND='DIR=`pwd|sed -e "s!$HOME!~!"`; if [ ${#DIR} -gt 30 ]; then CurDir=${DIR:0:12}...${DIR:${#DIR}-15}; else CurDir=$DIR; fi'
PS1="[\$CurDir] \$ "
The First Character of Each Directory
There is yet another method – I got this idea from the fish shell. In this approach, the big path will appear as…
[/v/w/h/s/L/l/w/p/e/langs] $ _
In this option, only the first character of each parent folder will be shown. Only the base folder name will be shown entirely. This is the approach I use. If you want to use this, open the ~/.bashrc file and add this…
PROMPT_COMMAND='CurDir=`pwd|sed -e "s!$HOME!~!"|sed -re "s!([^/])[^/]+/!\1/!g"`'
PS1="[\$CurDir] \$ "
Prompt Variables
The other values you can insert into the prompt are…
- \d
- the date in “Weekday Month Date” format (e.g., “Tue May 26″)
- \D{format}
- the format is passed to strftime(3) and the result is inserted into the prompt string; an empty format results in a locale-specific time representation. The braces are required
- \e
- an ASCII escape character (033)
- \h
- the hostname up to the first ‘.’
- \H
- the hostname
- \j
- the number of jobs currently managed by the shell
- \l
- the basename of the shell’s terminal device name
- \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
- \A
- the current time in 24-hour HH:MM format
- \u
- the username of the current user
- \v
- the version of bash (e.g., 2.00)
- \V
- the release of bash, version + patch level (e.g., 2.00.0)
- \w
- the current working directory, with $HOME abbreviated with a tilde
- \W
- the basename of the current working directory, with $HOME abbreviated with a tilde
- \!
- 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 control sequence into the prompt
- \]
- end a sequence of non-printing characters
Digg it
|
reddit
|
StumbleUpon
Tags: bash, command, customize, prompt, shell, terminal
Posted in Command Line, Configuration | 16 Comments »

Follow me(@binnyva) on Twitter
March 12th, 2009 at 8:25 am
For some reason the script to truncate the directory length does not work from me from within bashrc. If I issue it at the terminal itself it works. I’ve spent several hours trying to figure this out and making changes to no avail. If it helps any I’m using Ubuntu 8.10 and the terminal I’m in is in fact bash.
March 12th, 2009 at 7:37 pm
wyn
did you use export?
in any shell script you have to “export” your variables, so mine reads:
–[cut]–
export PROMPT_COMMAND=’DIR=`pwd|sed -e “s!$HOME!~!”`; if [ ${#DIR} -gt 30 ]; then CurDir=${DIR:0:12}…${DIR:${#DIR}-15}; else CurDir=$DIR; fi’
PS1=”[\$CurDir] \$ ”
–[/cut]–
excuse the line wrapping, but that should work.
March 12th, 2009 at 8:25 pm
@Wyn
I have the same issue. So far I’ve gotten the command to give the correct value for $CurDir, but it refuses to update. I fixed the command by replacing “!” chars with “|” chars in the sed script:
DIR=`pwd|sed -e “s|$HOME|~|”`
Still trying to get the update to work.
March 12th, 2009 at 8:57 pm
Ok. Figured it out. The default Ubuntu (& probaly Debian) .bashrc sets PROMPT_COMMAND later in the script to update the title of xterms. So this was overriding the new one. I combined them so that both happened. Here’s my new stuff:
PROMPT_COMMAND=’DIR=${PWD/$HOME/~}; if [ ${#DIR} -gt 30 ]; then CurDir=${DIR:0:12}…${DIR:${#DIR}-15}; else CurDir=$DIR; fi; export CurDir’
PS1=”\[33[01;32m\]\u\[33[00m\]@\[33[01;32m\]\h\[33[00m\]:\[33[01;36m\]\$CurDir\[33[00m\]\$ ”
That PS1 includes colors, which I like.
Then:
case “$TERM” in
xterm*|rxvt*)
PC2=’echo -ne “33]0;${USER}@${HOSTNAME}: ${PWD/$HOME/~}07″‘
PROMPT_COMMAND=”$PROMPT_COMMAND;$PC2″
;;
*)
;;
esac
Note: The export mentioned by @ejes above isn’t necessary.
Hope this helps.
March 12th, 2009 at 9:04 pm
So some of my last post was garbled. Also you should put quotes around the “${PWD/$HOME/~}” thing to get that to work. Just seemed easier than piping ‘pwd’ through ’sed’.
Thanks again for the tip!
March 12th, 2009 at 11:56 pm
aaaah that was it Paul, and yeah I had switched to piping myself in the DIR= statement, I didn’t bother mentioning it since nothing was working yet. Once I fixed that second Prompt_Command everything works beautifully, tyvm. Now I wonder if there’s a way to rig the output of pwd to put a \ before spaces in folder names (for the windows shares on my network)….
March 12th, 2009 at 11:58 pm
Oh, and for what it’s worth, my PS1 is a combination of colors, multilines, and this truncation:
PS1=’\n\[33[1;31m\] ${debian_chroot:+($debian_chroot)}\[33[1;31m\]\u@\h\[33[00m\]: \[33[01;34m\] $CurDir \[33[00m\]\n\[33[1;31m\] \t $ \[33[0;39m\]‘
March 13th, 2009 at 3:46 am
I use the last two components in the path. If you’re in /usr/local/man/man1 it will show just “man/man1″. That’s usually enough context for me.
I posted full details (including the bash function I wrote to implement this) on my blog a couple years ago
http://wemmick.blogspot.com/2006/09/geeky-friday-shorter-directory-path-in.html
March 15th, 2009 at 6:33 am
Nice article.
I hate one-line hacks.
Here’s an improvement:
_update_prompt () {
DIR=`pwd|sed -e “s!$HOME!~!”`
if [ ${#DIR} -gt 30 ]; then
CurDir=${DIR:0:12}…${DIR:${#DIR}-15}
else
CurDir=$DIR
fi
}
PROMPT_COMMAND=_update_prompt
PS1=”[\$CurDir] \$ ”
Also…
@ejes PROMPT_COMMAND does not need to be exported.
@wyn Make sure your ~/.profile or ~/.bash_profile sources ~/.bashrc. From Debian’s default .profile:
# if running bash
if [ -n "$BASH_VERSION" ]; then
# include .bashrc if it exists
if [ -f "$HOME/.bashrc" ]; then
. “$HOME/.bashrc”
fi
fi
March 28th, 2009 at 12:36 am
[...] is part two of the ‘Customizing the Terminal’ series. Part one is ‘Customizing the Terminal: The Prompt‘. In this part, we’ll see how to create aliases to make working in the console [...]
March 28th, 2009 at 11:19 pm
[...] text links. If you get the favicons of the sites you’re linking to, it will look a lot nicer. Example (go to the end of the post). You can use bigger images as well – example. Or use some kind of [...]
March 29th, 2009 at 10:07 am
[...] the terminal - Parts I and II - Binny writes on how you can customize the terminal prompt and add [...]
April 13th, 2009 at 1:10 am
[...] Customizing the Terminal: The Prompt [...]
July 18th, 2009 at 1:01 pm
Thanks!
This is awesome!
-Matt
July 18th, 2009 at 9:56 pm
Oops. I tried the last approach (which you use) and got this error on my Mac, running OS X 10.5.7
sed: illegal option — r
usage: sed script [-Ealn] [-i extension] [file ...]
sed [-Ealn] [-i extension] [-e script] … [-f script_file] … [file ...]
July 18th, 2009 at 10:00 pm
Hmmm… a quick man sed and a guess…
changed -re to -E and seems to work now…
PROMPT_COMMAND=’CurDir=`pwd|sed -e “s!$HOME!~!”|sed -E “s!([^/])[^/]+/!\1/!g”`’
PS1=”[\$CurDir] \$ ”
nice.