Prevent Mac terminal brightening font color with no background

When I execute echo -e '\033[49;36m\u2588\033[40;36m\u2588' in a linux terminal, I get two blocks of the same color:

linux colored blocks

Here, the first block has no background color (49) while the second block has a black background color. The character displayed should generally take up the entire space, so the background is not visible and they appear the same.

However, if I repeat this in Mac Terminal I get something very surprising:

enter image description here

For some reason, mac terminal is changing the foreground color for different background colors. Through some experimentation, I've found that the foreground color is constant for any fixed background color, and only different for the default background color. The color it renders is distinct from any of the other dim or bright modifications offered by ansi terminals.

Why is this happening, and more importantly, can I fix it?


Solution 1:

Short answer: don't use "compound" color codes like \033[49;36m, use separated colour instructions like \033[0;42m\033[0;36m instead. The difference can be nicely seen by comparing the output of those two commands:

echo -e "\033[0;42;36m\xe2\x96\x88\033[0;49;36m\xe2\x96\x88"
echo -e "\033[0;42m\033[0;36m\xe2\x96\x88\033[0;49;36m\xe2\x96\x88"

(note that my version of bash could not process \u2588, so I had to resort to the hex variant \xe2\x96\x88).

Suggestion for future code:

Create a file (for example in ~/.bash_color_definitions) with the following content:

# Setup some colors to use later in interactive shell or scripts

# Color reset:
export COLOR_RESET='\033[0m' # reset color

# foreground colors

export FG_WHITE='\033[1;37m'
export FG_BLACK='\033[0;30m'
export FG_BLUE='\033[0;34m' 
export FG_LIGHT_BLUE='\033[1;34m'
export FG_GREEN='\033[0;32m'
export FG_LIGHT_GREEN='\033[1;32m'
export FG_CYAN='\033[0;36m'
export FG_LIGHT_CYAN='\033[1;36m'
export FG_RED='\033[0;31m'
export FG_LIGHT_RED='\033[1;31m'
export FG_PURPLE='\033[0;35m'
export FG_LIGHT_PURPLE='\033[1;35m'
export FG_BROWN='\033[0;33m'
export FG_YELLOW='\033[1;33m'
export FG_GRAY='\033[1;30m'
export FG_LIGHT_GRAY='\033[0;37m'


# background colors

export BG_WHITE='\033[1;47m'
export BG_BLACK='\033[0;40m'
export BG_BLUE='\033[0;44m' 
export BG_LIGHT_BLUE='\033[1;44m'
export BG_GREEN='\033[0;42m'
export BG_LIGHT_GREEN='\033[1;42m'
export BG_CYAN='\033[0;46m'
export BG_LIGHT_CYAN='\033[1;46m'
export BG_RED='\033[0;41m'
export BG_LIGHT_RED='\033[1;41m'
export BG_PURPLE='\033[0;45m'
export BG_LIGHT_PURPLE='\033[1;45m'
export BG_BROWN='\033[0;43m'
export BG_YELLOW='\033[1;43m'
export BG_GRAY='\033[1;40m'
export BG_LIGHT_GRAY='\033[0;47m'

And source it on every bash start by putting source ~/.bash_color_definitions into your .bashrc or .bash_profile. Then start producing more readable code like this:

 echo -e "$BG_BLACK$FG_CYAN\xe2\x96\x88$BG_GRAY$FG_CYAN\xe2\x96\x88$COLOR_RESET"

EDIT:

Turns out, the code in my answer actually reset the background (as Erik noted in the comments). After a bit of testing, it appears that the Mac Terminal "mixes" the foreground/background colours a bit different when you try to use color code 49, i.e. the "default background color".

iTerm.app for example does not behave in this way, so you could easily switch terminals, if you want to.

A valid solution, however, is to fully specify the background color (i.e. don't just use 49;36m, use 47;36m if your background is white). Or better use the xterm-256color color specifications; that is \033[38;5;___m for the foreground and \033[48;5;___m for the background colours (replacing the underscore with a number in 0-255). At least on my computer, this then produces consistent colours:

echo -e "\033[48;5;256m\033[38;5;6m\xe2\x96\x88\033[40;36m\033[38;5;6m\xe2\x96\x88\033[0m"

If you want to check which ANSI xterm-256color best matches your actual background color, you could use this script (modified version from the one found here):

#!/bin/bash

for fgbg in 38 48 ; do #Foreground/Background
    for color in {0..256} ; do #Colors
        #Display the color
        echo -e "\033[${fgbg};5;${color}m ${color}\t\033[0m"
    done
    echo #New line
done

exit 0