'ANSI Color Specific RGB Sequence Bash

I know that in bash terminals a reliable way to change color is using ANSI escape sequences. For example:

echo -e "\033[0;31mbrown text\033[0;00m"

should output

brown text (in brown)

Is there a way to output color using a specific RGB set with ANSI? Say I want bright red:

echo -e "**\033[255:0:0m**red text\033[0;00m"

Does this sort of thing exist?

I just want to use standard bash.



Solution 1:[1]

This does exist, but instead of the 16777216 (256^3) colors that the OP was looking for, there are 216 (6^3) equally distributed colors, in a larger set of 256 colors. Example:

echo -e "\033[38;5;208mpeach\033[0;00m"

This will output a pleasing sort of peach colored text.


Taking apart this command: \033[38;5;208m

The \033 is the escape code. The [38; directs command to the foreground. If you want to change the background color instead, use [48; instead. The 5; is just a piece of the sequence that changes color. And the most important part, 208m, selects the actual color.


There are 3 sets of colors that can be found in the 256 color sequence for this escape. The first set is the basic "candy" color set, or values 0-15. Then there is a cube of distributed colors, from 16-231. Lastly there is a detailed grayscale set from 232-255.

You can find a table with all of these values here: http://bitmote.com/index.php?post/2012/11/19/Using-ANSI-Color-Codes-to-Colorize-Your-Bash-Prompt-on-Linux#256%20(8-bit)%20Colors

Solution 2:[2]

Both answers here fail to mention the Truecolor ANSI support for 8bpc color. This will get the RGB color the OP originally asked for.

Instead of ;5, use ;2, and specify the R, G, and B values (0-255) in the following three control segments.

\x1b[38;2;40;177;249m

To test if your terminal supports Truecolor:

printf "\x1b[38;2;40;177;249mTRUECOLOR\x1b[0m\n"

On my machine, XTerm happily outputted the correct color; although, terminals that are modeled after terminals that predate modern RGB color generally will not support truecolor - make sure you know your target before using this particular variant of the escape code.


I'd also like to point out the 38 and the ;5/;2 - Blue Ice mentioned that 38 routes and then 5 changes the color. That is slightly incorrect.

38 is the xterm-256 extended foreground color code; 30-37 are simply 16-color foreground codes (with a brightness controlled by escape code 1 on some systems and the arguably-supported 90-97 non-standard 'bright' codes) that are supported by all vt100/xterm-compliant colored terminals.

The ;2 and ;5 indicate the format of the color, ultimately telling the terminal how many more sequences to pull: ;5 specifying an 8-bit format (as Blue Ice mentioned) requiring only 1 more control segment, and ;2 specifying a full 24-bit RGB format requiring 3 control segments.

These extended modes are technically "undocumented" and are completely implementation defined. As far as I know and can research, they are not governed by the ANSI committee.


For the so inclined, the 5; (256 color) format starts with the 16 original colors (both dark/light, so 30-37 and 90-97) as colors 0-15.

The proceeding 216 colors (16-231) are formed by a 3bpc RGB value offset by 16, packed into a single value.

The final 24 colors (232-256) are greyscale starting from a shade slightly lighter than black ranging up to a shade slightly darker than white. Some emulators interpret these steps as linear increments from (256 / 24) on all three channels, though I've come across some emulators that seem to explicitly define these values.

Here is a Javascript function that performs such a conversion, taking into account all of the greys.

function rgbToAnsi256(r, g, b) {
    // we use the extended greyscale palette here, with the exception of
    // black and white. normal palette only has 4 greyscale shades.
    if (r === g && g === b) {
        if (r < 8) {
            return 16;
        }

        if (r > 248) {
            return 231;
        }

        return Math.round(((r - 8) / 247) * 24) + 232;
    }

    var ansi = 16
        + (36 * Math.round(r / 255 * 5))
        + (6 * Math.round(g / 255 * 5))
        + Math.round(b / 255 * 5);

    return ansi;
}

So in a way, you can calculate 256 ANSI colors from initial RGB values by reducing them from 8 to 3 bits in order to form a 256 encoded value in the event you want to programmatically do so on terminals that do not support Truecolor.

Solution 3:[3]

This will work

echo -e "**\033[38;2;255;0;0m**red text\033[0;00m"

format: "\033[38;2;R;G;Bm"

  • R is your RED component of your RGB
  • G is your GREEN component of your RGB
  • B is your BLUE component of your RGB

Solution 4:[4]

Currently true color escape sequences (\e[38;2;R;G;Bm) are supported by certain terminal emulators including gnome-terminal (with vte >= 0.36), konsole, and st [suckless].

The feature is not supported by certain others, e.g. pterm [putty], terminology [enlightenment], urxvt.

xterm is halfway in between: it recognizes the escape sequences, but rounds every color to the nearest one in the 256-color palette.

Solution 5:[5]

No there's not.

And to nitpick, those are technically not "ANSI escape sequences" but VT100 control codes (which were defined long before there were graphical terminals and terms like "RGB").

Solution 6:[6]

Playing with RGB (and HSV) in

ANSI sequences in terminal.

There are two way of printing colors in bash.

After playing with nice tools found on xterm's source tree, here is how vttests/256colors2.pl show on my gnome-terminal:

vttests/256colors2.pl

this use ANSI syntax \e[48;5;COLORm:

printf '\e[48;5;%sm' $color;

instead of \e[48;2;RED;GREEN;BLUEm:

printf '\e[48;2;%s;%s;%sm' $red $green $blue;

I've done some functions to play with RGB, and HSV:

RGB to HSV

hsv() {
    local -n _result=$4
    local -i _hsv_min _hsv_t
    local _hsv_s
    local -i _hsv_max=" $1 > $2 ?
                (_hsv_min=($2 > $3 ? $3:$2 ), ( $1 > $3 ? $1 : $3 )) :
                (_hsv_min=($1 > $3 ? $3:$1 ), $2) > $3 ? $2 : $3 "
    case $_hsv_max in 
        $_hsv_min) _hsv_t=0 ;;
        $1) _hsv_t=" ( 60 * ( $2 - $3 ) / ( _hsv_max-_hsv_min )+ 360 )%360";;
        $2) _hsv_t=" 60 * ( $3 - $1 ) / ( _hsv_max-_hsv_min )+ 120 " ;;
        $3) _hsv_t=" 60 * ( $1 - $2 ) / ( _hsv_max-_hsv_min )+ 240 " ;;
    esac
    _hsv_s=0000000$(( _hsv_max==0?0 : 100000000-100000000*_hsv_min / _hsv_max ))
    printf -v _hsv_s %.7f ${_hsv_s::-8}.${_hsv_s: -8}
    _result=($_hsv_t $_hsv_s $_hsv_max)
}

Then

RED=255 GREEN=240 BLUE=128
hsv $RED $GREEN $BLUE hsvAr
echo ${hsvAr[@]}
52 0.4980392 255
printf 'Hue: %d, Saturation: %f, Value: %d\n' "${hsvAr[@]}"
Hue: 52, Saturation: 0.498039, Value: 255

HSV to RGB

rgb() {
    local -n _result=$4
    local -i _rgb_i=" (($1%360)/60)%6 "
    local -i _rgb_f=" 100000000*($1%360)/60-_rgb_i*100000000 "
    local _rgb_s
    printf -v _rgb_s %.8f "$2"
    _rgb_s=$((10#${_rgb_s/.}))
    local -i _rgb_l=" $3*(100000000-_rgb_s)/100000000 "
    case $_rgb_i in
        0 )
            local -i _rgb_n="$3*(100000000-(100000000-_rgb_f)*_rgb_s/100000000)/
                                100000000 "
            _result=("$3" "$_rgb_n" "$_rgb_l") ;;
        1 )
            local -i _rgb_m=" $3*(100000000-_rgb_f*_rgb_s/100000000)/100000000 "
            _result=("$_rgb_m" "$3" "$_rgb_l") ;;
        2 )
            local -i _rgb_n="$3*(100000000-(100000000-_rgb_f)*_rgb_s/100000000)/
                                100000000 "
            _result=("$_rgb_l" "$3" "$_rgb_n") ;;
        3 )
            local -i _rgb_m=" $3*(100000000-_rgb_f*_rgb_s/100000000)/100000000 "
            _result=("$_rgb_l" "$_rgb_m" "$3") ;;
        4 )
            local -i _rgb_n="$3*(100000000-(100000000-_rgb_f)*_rgb_s/100000000)/
                                100000000 "
            _result=("$_rgb_n" "$_rgb_l" "$3") ;;
        * )
            local -i _rgb_m=" $3*(100000000-_rgb_f*_rgb_s/100000000)/100000000 "
            _result=("$3" "$_rgb_l" "$_rgb_m") ;;
    esac
}

Then

rgb 160 .6 240 out
echo ${out[@]}
96 240 192
printf '\e[48;5;%d;%d;%dm    \e[0m\n' "${out[@]}"

Will produce a bunch of colored spaces.

Further: hsvrgb-browser.sh

Preamble: Store previous two function into a file called hsvrgb.sh, stored in same directory than downloaded hsvrgb-browser.sh.

enter image description here

HSV-RGB Color browser - Usage: 

  [RrGgBbVb] Incrase/decrase value by step ('1'), from 0 to 255..
  [HhTt]     Incrase/decrase Hue (tint), loop over 0 - 359.
  [Ss]       Increase/decrase Saturation by .006 x step (1).
  [Cc]       Toggle Color bar rendering (upper C fix HSV)
  [+-]       Incrase/decrase step.
  [u]        show this.
  [q]        quit.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 dimo414
Solution 2
Solution 3 vallentin
Solution 4 egmont
Solution 5 Some programmer dude
Solution 6