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:
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:
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