In my .bashrc, I use ANSI terminal color codes to colorize various bits. It looks like this:

PS1='\u@\h:\w\[\033[33m\]$(virtual_env)\[\033[32m\]$(git_branch)\[\033[0m\]$ '

where virtual_env and git_branch are bash functions that output stuff on stdout.

Now, to make it easier to read and modify, I'd like to store the color codes in variables and refer to them, instead of embedding them directly into PS1. So I have a bunch of variables like this:


I'd like to be able to write something like:

PS1='\u@\h:\w${YELLOW}$(virtual_env)${GREEN}$(git_branch)${RESET}$ '

But this doesn't work -- the color codes show up in the prompt, like they're escaped. The colors work correctly if I use double quotes instead for PS1, but then the prompt only changes when I do source ~/.bashrc.

I've tried other things I've seen people do -- using printf, using single quotes for the colors, putting the \[ and \] in PS1 instead of the color variable, but nothing seems to work.

How can I use variables for the color codes?

  • Can you give us your .bashrc?
    – cuonglm
    Jul 3, 2014 at 18:51
  • @cuonglm All your .bashrc are belong to us? I'll show myself out.
    – CivFan
    May 25, 2016 at 16:39

3 Answers 3


The solution is to get the shell to substitute the color variables when defining the prompt, but not the functions. To do this, use the double quotes as you had originally tried, but escape the commands so they aren't evaluated until the prompt is drawn.

PS1="\u@\h:\w${YELLOW}\$(virtual_env)${GREEN}\$(git_branch)${RESET}$ "

Notice the \ before the $() on each command.

If we echo this out, we see:

echo "$PS1"

As you can see, the color variables got substituted, but not the commands.

  • 1
    This doesn't seem to work if $(git_branch) also is trying to print using ${YELLOW} etc. In that section alone, you'll still get all the [] characters.
    – W. B. Reed
    Feb 27, 2018 at 19:40

The problem is that your variable GREEN contains the literal string consisting of "backslash bracket backslash zero three three" and so on. It does not contain for example an ASCII escape character as required to get your terminal to change colour.

You could put control characters into GREEN (and YELLOW and RESET) manually, but a much better option is to use tput in the first place so that you do not need to hard code anything and you will support any terminal type.

GREEN="$(tput setaf 2)"
YELLOW="$(tput setaf 3)"
RESET="$(tput setaf 0)"

The reason why it world when you put "backslash zero three three" etc... directly into PS1 is that interpretation of certain backslash sequences is a feature of bash's prompting (see the section PROMPTING in the manual. This substitution occurs before parameter expansion, command substitution, arithmetic expansion, and quote removal, though, so it's not applied to the results of all those other operations.

  • 6
    When doing it this way, you need to wrap the color variables in \[\] inside the $PS1. For example: PS1='\u@\h:\w\[${YELLOW}\]'. If you don't do this, and you end up with a long command that wraps to the next line, you'll encounter all sorts of issues. The shell uses the \[\] to determine which characters are non-printable, so it doesn't factor them into the calculation of the prompt length. It needs this so it can properly draw the line when it exceeds the terminal width.
    – phemmer
    Jul 3, 2014 at 18:58
  • I didn't know about tput, thanks. I'll use Patrick's answer for now but I'll revisit this when I get a chance. Jul 3, 2014 at 19:38

Change the way you fill $GREEN, $YELLOW and $RESET:

GREEN="$(echo -e "\033[32m")"
YELLOW="$(echo -e "\033[33m")"
RESET="$(echo -e "\033[0m")"

PS1='\u@\h:\w${YELLOW}$(virtual_env)${GREEN}$(git_branch)${RESET}$ '
  • 1
    This in effect does the exact same thing as Celada's answer. But Celada's is more portable in case the terminal uses different escape codes for color setting. It's also going to have the same issue with the multi-line prompt thing.
    – phemmer
    Jul 3, 2014 at 19:23
  • 3
    The \[…\] bit needs to remain in the prompt, you can't stuff it in a variable. You've removed it altogether, which will result in display problems (the cursor not being in the position where bash expects it). Jul 3, 2014 at 23:40
  • Aside from @Patrick concerns, echo -e is not portable. Jul 4, 2014 at 7:12
  • 1
    With non-portability comes more features -- tput setaf doesn't let you choose from the "light" set of colors, such as light cyan. @Cyrus's answer, however, does.
    – CivFan
    May 25, 2016 at 16:47

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .