256 Colors in Terminal – How to Use for Background

ansicolorsgnome-terminatorterminalzsh

I know how to use 256 colors for text in terminal:

printf "\033[38;5;196mhello\n"

But for background color, I seem to be limited to the basic 8 colors only, ie:

printf "\033[41mhello\n"

How can I use 256 colors for background colors as well ?

I mean, the terminal already know the colors, so it should be possible. But what is the syntax?

In case it is relevant, I am using terminator as my terminal emulator, and zsh as my shell.

Best Answer

In zsh, you don't need to hardcode escape sequences as it has several builtin ways to set the background and foreground colours.

You can use echoti setaf to set the terminal ansi foreground colour and echoti setab to set the background one (setaf and setab being the names of the corresponding terminfo capabilities)

Assuming your terminal supports 256 colours (as VTE-based ones such as your gnome-terminator do) and $TERM is correctly set to a value that identifies a terminfo entry with the right escape sequences for that, it should work.

$ echoti setab 196 | sed -n l
\033[48;5;196m$

Or you can use prompt expansion with print -P or the % parameter expansion flag and:

$ print -rP '%K{196}' | sed -n l
\033[48;5;196m$

(here sed -n l is used to reveal the corresponding escape sequence that is being sent, $ is just to show where the line ends, it's not part of the output, \033 is GNU sed's l command's representation of the ESC character (with octal 033 byte value in ASCII))

Some terminals (including VTE-based ones such as your gnome-terminator) also support RGB specifications. On those, you could do

$ print -rP '%K{#ffffff}' | sed -n l
\033[48;2;255;255;255m$

(here with fffffff for bright white as that's ff the maximum value for all of the red, green and blue components). In that case, zsh hardcodes the xterm-style sequence (see there for the background) as there is no corresponding terminfo capability. Though not standard, that's currently the most widely supported across modern FLOSS terminal emulators.

%K sets the background colour, %F for foreground. %k/%f restore the default colour.

For terminals that don't support that but do support the 88 or 256 colour palette, zsh also has a zsh/nearcolor module to get you the colour nearest to that RGB specification:

$ zmodload zsh/nearcolor
$ echoti colors
256
$ print -rP '%K{#ffffff}' | sed -n l
\033[48;5;231m$

(here colour 231 on my 256 colour terminal is the closest one to bright white, it is actually bright white).

If you have access to the X11 rgb.txt file, you could also define associative arrays for each of the X11 colour names with something like:

typeset -A X11_bg X11_fg
while read -r r g b c; do
  [[ $r = [0-9]* ]] || continue
  printf -v hex %02x $r $g $b
  X11_fg[$c]=${(%):-%F{#$hex}}
  X11_bg[$c]=${(%):-%K{#$hex}}
done < /etc/X11/rgb.txt
X11_bg[default]=${(%):-%k} X11_fg[default]=${(%):-%f}

(Debian-like systems have /etc/X11/rgb.txt as part of the x11-common package).

To do things like:

print -r "$X11_bg[dark olive green]text$X11_bg[default]"

For more details, see:

  • man 5 terminfo
  • info zsh echoti
  • info zsh print
  • info zsh "Prompt Expansion"
  • info zsh "The zsh/nearcolor Module"

(beware that on some systems, you need to install a zsh-doc package or equivalent for the info pages to become available).

Related Question