Bash Terminal – Where Are Terminal Color Escape Sequences Defined?

bashcolorsterminal

I've used every so often colors in Bash scripting (mostly on CentOS), but to make their usage more convinient I end up redefining variables to color values:

local GRAY="\[\033[1;30m\]"
local LIGHT_GRAY="\[\033[0;37m\]"
local CYAN="\[\033[0;36m\]"
local LIGHT_CYAN="\[\033[1;36m\]"
local NO_COLOUR="\[\033[0m\]"

or also with tput:

bold=`tput bold`
normal=`tput sgr0`
whitef=`tput setaf 7`
greenf=`tput setaf 2`
redb=`tput setab 1`

I've grep'ed around the /etc/rc.d/init.d directory but didn't find anything related to color definitions in there.

Is there such definition already in place? If not I would put them into a file in /etc/rc.d/init.d for say, and have it included in my scripts, a bit like with /etc/rc.d/init.d/functions

Best Answer

There are several aspects at play in what you're asking.

First, bash doesn't define colors. In fact bash has absolutely no idea that colors even exist. All it knows is that you told it to output the characters \033[0;36m. Your terminal emulator (xterm, gnome-terminal, whatever) receives these characters and understands "I need to start outputting in cyan".

Thus it is your terminal emulator that understands colors. Your terminal emulator understands that \033[0;36m is cyan, but another terminal emulator might use an entirely different set of characters for cyan (though no sane terminal emulator would flaunt the standard and do this). This is the reason for tput. When you run tput setaf 6, tput is going to look up your terminal's escape codes for the color 6 (cyan), and output that escape code.
(see this question for more info on tput setaf codes)

Now back to bash. As you may have noticed, when I've been referring to the cyan color, I've been using \033[0;36m, not \[\033[0;36m\]. The square brackets have been missing. The purpose of the square brackets is that when using escape codes (colors) in the prompt, bash has to know which characters are non-printing (zero-width, don't actually show anything). Thus you enclose non-printing characters in \[ \]. If you remove these characters, everything might appear to work just fine at first, but you'll start running into all sorts of weirdness when your command exceeds the terminal width. This is because when typing, bash has to know when the command should wrap to the next line. To do this, it calculates the width of the prompt, and then the width of how much you've typed.

Another note, about tput. CYAN="\[\033[0;36m\]" is not the same thing as CYAN="$(tput setaf 6)". As we just discussed, the square brackets are relevant to bash, and tput is only going to output the terminal escape codes.

Since square brackets are usually only relevant in the prompt, if you're using colors in the output of a script or something, you should not use them. Meaning that if you're going to be using colors for more than prompts, you need to define multiple variables. One with square brackets for using in the prompt, and one without for everything else. Though you could just manually add the square brackets every time you reference a color in the prompt.

So long story short, you probably want to define something like:

local CYAN="$(tput setaf 6)" # OR CYAN="\033[0;36m"
local LIGHT_CYAN="$CYAN$(tput bold)" # OR LIGHT_CYAN="\033[1;36m"
local PROMPT_CYAN="\[$CYAN\]"
local PROMPT_LIGHT_CYAN="\[$LIGHT_CYAN\]"
Related Question