Skip to main content
7 of 7
added 890 characters in body

ANSI Colors on console term

Preamble: about $TERM variable

Verify your environment with: tput colors

If you use some compatible xterm console, your $TERM may contain something like xterm*:

echo $TERM xterm tput colors 8 

Further demos won't work: you will get image looking like:

bad no colored output

unless you set this to xterm-256color:

export TERM=xterm-256color ; reset tput colors 256 

( You could even try to run this after setting export TERM=xterm-mono ;)

Doing simply the job by using tput

Depending on wich term protocol your console use, sequence could be: \e[38;5;XXXm or \e[3XXXm where XXX correspond to ansi number.

To ensure you use the right ANSI sequence, you have to use tput.

Regarding to Wikipedia's ANSI escape code, I wrote this:

#!/bin/bash for ((i=0; i<256; i++)) ;do echo -n ' ' tput setab $i tput setaf $(( ( ( i > 231 && i < 244 ) || ( ( i < 17 ) && ( i % 8 < 2 ) ) || ( i > 16 && i < 232 ) && ( ( i - 16 ) % 6 * 11 + ( i - 16 ) / 6 % 6 * 14 + ( i - 16 ) / 36 * 10 ) < 58 ) ? 7 : 16 )) printf " C %3d " $i tput op (( ((i<16||i>231) && ((i+1)%8==0)) || ((i>16&&i<232)&& ((i-15)%6==0)) )) && printf "\n" done 

Should render something like:

256 colors ansi term

Optimizing : reducing forks by running tput as background process

... Then, because I hate runnig more than 200 forks in a little script, I wrote this:

#!/bin/bash # Connector fifos directory read TMPDIR < <(mktemp -d /dev/shm/conn_shell_XXXXXXX) fd=3 # find next free fd nextFd() { while [ -e /dev/fd/$fd ];do ((fd++)) ;done;printf -v $1 %d $fd;} tputConnector() { mkfifo $TMPDIR/tput nextFd TPUTIN eval "exec $TPUTIN> >(LANG=C exec stdbuf -o0 tput -S - >$TMPDIR/tput 2>&1)" nextFd TPUTOUT eval "exec $TPUTOUT<$TMPDIR/tput" rm $TMPDIR/tput rmdir $TMPDIR } myTput() { echo -e "$1\ncr" 1>&$TPUTIN && IFS= read -r -d $'\r' -u $TPUTOUT $2 } tputConnector myTput op op myTput "setaf 7" grey myTput "setaf 16" black fore=("$black" "$grey") for ((i=0; i<256; i++)) ;do myTput "setab $i" bgr printf " %s%s %3d %s" "$bgr" "${fore[ i>231 && i<244||(i<17)&& (i%8<2)|| (i>16&&i<232)&&((i-16)%6*11+(i-16)/6%6*14+(i-16)/36*10)<58 ? 1 : 0 ]}" $i "$op" (( ((i<16||i>231) && ((i+1)%8==0)) || ((i>16&&i<232)&& ((i-15)%6==0)) )) && printf "\n" '' done 

With only 1 fork! Same result, but approx 10x faster!

If first script run in ~1.12 second on my desk, they take upto ~47.4 seconds on my raspberry-pi!!

While second script run in ~0.11 second on my desk and ~4.97 seconds on my raspberry.

Without forks, using ansi sequences

From 8-bit color chapter of Wikipedia's ANSI escape code:

#!/bin/bash for ((i=0; i<256; i++)) ;do fg=$((((i>231&&i<244)||((i<17)&&(i%8<2))||(i>16&&i<232)&&((i-16)%6*11+ (i-16)/6%6*14+(i-16)/36*10)<58)?7:16)) printf ' \e[48;5;%d;38;5;%dm C %3d \e[49;39m' $i $fg $i (( ((i<16||i>231) && ((i+1)%8==0)) || ((i>16&&i<232)&& ((i-15)%6==0)) )) && printf "\n" done 

Note: On my raspberry, this script take approx 1.5 seconds to complete.

Same but without loop:

Could be quicker again:

#!/bin/bash shape='XXXXXXXX' arry=(0 0 2{,,}{,,}{,,,} 0{,,}) eval arry=(${arry[@]/?/\${shape:&\}}) printf -v shape '%s\n' "${arry[@]//X/ \\e[48;5;%d;38;5;%%%%dm C %%3d \\e[0m}" declare -ai arry=({0..255}) printf -v shape "$shape" ${arry[@]} printf -v shape "$shape" ${arry[@]} eval "arry=(${arry[@]/*/\"(&>231\&\&&<244)||((&<17)\&\&(&%8<2))||(&>16\&\& &<232)\&\&((&-16)%6*11+(&-16)/6%6*14+(&-16)/36*10)<58?7:16\"})" printf "$shape" ${arry[@]} 

Note: this could by cut'n pasted into a fresh terminal window.

Then this version will print same output, but in ~0.6 second on my raspberry pi.

Explained:

  • Building a shape of 41 lines with two first lines of 8 fields, followed by 36 lines of 6 fields, then 3 lines of 8 fields.
     shape='XXXXXXXX' # some 8 X string arry=(0 0 2{,,}{,,}{,,,} 0{,,}) # 2(x8) + 36(x6) + 3(x8): 41 lines eval arry=(${arry[@]/?/\${shape:&\}}) # 'arry=(XXXXXXXX XXXXXXXX XXXXXX ..' printf -v shape '%s\n' "${arry[@]//X/ \\e[48;5;%d;38;5;%%%%dm C %%3d \\e[0m}" 
    • replace each X by a format string for 3 values:
    • add a newline \n after each group of transformed X
    • %d will be ANSI color resolved first, then
    • %%3d for right aligned label, and
    • %%%%d for the foreground color.
  • Converting $arry into an integer array containing values from 0 to 255
    declare -ai arry=({0..255}) 
  • Populate background colors (%d)
     printf -v shape "$shape" ${arry[@]} 
  • Populate labels (%%d)
     printf -v shape "$shape" ${arry[@]} 
  • Compute 256 foreground colors into (integer) array $arry
     eval "arry=(${arry[@]/*/\"(&>231\&\&&<244)||((&<17)\&\&(&%8<2))||(&>16\&\& &<232)\&\&((&-16)%6*11+(&-16)/6%6*14+(&-16)/36*10)<58?7:16\"})" 
  • Populate finalised shape with foregrounds and print out.
     printf "$shape" ${arry[@]} 

Note: as this don't refer to tput, environment variable TERM doesn't matter.