Friday, November 21, 2008

Setting up a Pretty Bash Prompt in Linux

I've been using a command line for a few years now, but only recently did I start experimenting with customizing my prompt. I've built up what I think is a useful and pretty prompt, so I figure it's only right to share it.

Normally, this will show the username and hostname in green, followed by the path and the dollar in blue.

chris@linuxbox:~/some/directory $

If there are jobs running the background, the count shows up in cyan braces before the dollar.

chris@linuxbox:~/some/directory {2}$

If the last command had a non-zero return value, it is shown in red brackets before the dollar.

chris@linuxbox:~/some/directory {2}[130]$

Finally, if the user is root (effective user ID 0), the username and hostname are shown in red rather than green.

root@linuxbox:~/some/directory {2}[130]$

Most of the fun happens in /etc/bashrc. This file is included by the default .bashrc file for all users on my box.

# Extract from /etc/bashrc

# If non-zero, print the last command's return value
function _prompt_print_return()
{
if [ "$_prompt_return" -ne 0 ]
then
echo -n "[$_prompt_return]"
fi
}

# If non-zero, print the number of currently running jobs
function _prompt_print_jobs()
{
local j=$(jobs | wc -l | awk '{ print $1 }')

if [ "$j" -ne 0 ]
then
echo -n "{$j}"
fi
}

# Set the prompt color depending on the user's root-ness
function _prompt_color()
{
if [ $EUID -eq 0 ]
then
color=31
else
color=32
fi

echo -e -n "\033[1;${color}m"
}

# Note that I've split $PS1 onto several lines.
# If you combine onto one line, remove the backslashes at the end of lines
export PS1="\[\$(_prompt_color)\]\u@\h\[\033[1;34m\]:\w \[\033[1;36m\]\
\$(_prompt_print_jobs)\[\033[1;31m\]\$(_prompt_print_return)\
\[\033[1;34m\]\$\[\033[00m\] "

export PS2="\[\033[1;34m\]>\[\033[00m\] "
export PS3="\[\033[1;34m\]#?\[\033[00m\] "
export PS4="\[\033[1;34m\][\${LINENO}]+\[\033[00m\] "


To include this, I put the following in my .bashrc

# Excerpt from ~/.bashrc

# Run the global bashrc if it exists
if [ -f /etc/bashrc ]
then
. /etc/bashrc
fi


For some added fun, I wanted to have the prompt set the xterm's title bar. So in my ~/.bashrc, I added the following

# Excerpt from ~/.bashrc

export PS1="\[\033]0;\u@\h:\w\007\]$PS1"


That escape sequence sets the title to whatever is between the semicolon and \007 (ASCII 7). But that wasn't enough for me. When a command is running, I wanted the command and the current path to be in the title. So I added this to my ~/.bashrc

# Excerpt from ~/.bashrc

trap 'echo -ne "\033]0;$BASH_COMMAND [$(pwd)]\007"' DEBUG


The DEBUG signal is sent when a command is about to be run, and $BASH_COMMAND contains the string the user entered at the prompt. Note that this has not worked on every system I've tried. On my Mac, it works for a login shell, but if you run a sub-shell it prints some nonsense. It works beautifully on my Gentoo box.

So there you have it, a functional and pretty prompt for your command line. The parts that directly relate to printing the prompt have worked on every system I've tried. The parts relating to setting the xterm title seem more fragile. Your mileage may vary.

Labels: , ,