Bash – Using Variables to Store Terminal Color Codes for PS1

bashenvironment-variablespromptterminal

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:

GREEN="\[\033[32m\]"
YELLOW="\[\033[33m\]"
RESET="\[\033[0m\]"

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?

Best Answer

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"
\u@\h:\w\[\033[33m\]$(virtual_env)\[\033[32m\]$(git_branch)\[\033[0m\]$ 

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

Related Question