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:
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:
Optimizing bash: 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
Xby a format string for 3 values: - add a newline
\nafter each group of transformedX %dwill be ANSI color resolved first, then%%3dfor right aligned label, and%%%%dfor the foreground color.
- replace each
- Converting
$arryinto an integer array containing values from0to255declare -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
$arryeval "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.

