Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

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?

share|improve this question
    
Can you give us your .bashrc? –  cuonglm Jul 3 at 18:51

3 Answers 3

up vote 12 down vote accepted

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.

share|improve this answer
1  
This works great, thanks! –  Ismail Badawi Jul 3 at 19:37

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.

share|improve this answer
3  
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. –  Patrick Jul 3 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. –  Ismail Badawi Jul 3 at 19:38
    
+1 For suggesting tput. –  helpermethod Jul 4 at 7:12

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}$ '
share|improve this answer
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. –  Patrick Jul 3 at 19:23
    
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). –  Gilles Jul 3 at 23:40
    
Aside from @Patrick concerns, echo -e is not portable. –  helpermethod Jul 4 at 7:12

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.