Version 1 of Colors in Unix Shells

Updated 2012-11-09 08:50:18 by rui

Using colors when printing text to a console can be quite helpful for a program's users and, under Unix-like operating systems, it is natively supported by almost any shell.

The following code shows the ccolor namespace containing several variables with common color codes and a procedure for parsing text containing tags.


# ########################################################################### #
# Description:
#  This namespace contains console color codes defined in variables which 
#  can be used for adding color in text strings.
#  Additionally, it contains a procedure which replaces certain tags in a 
#  text with their corresponding color codes, making the resulting string 
#  suitable for dumping to a console supporting colors.
#  |-------------------|--------------------|------------------|
#  |Effects            |Foreground Colors   |Background Colors |
#  |-------------------|--------------------|------------------|
#  |bold       : \e[1m |black      : \e[30m |black   : \e[40m  |
#  |-------------------|--------------------|------------------|
#  |dim        : \e[2m |red        : \e[31m |red     : \e[41m  |
#  |-------------------|--------------------|------------------|
#  |underlined : \e[4m |green      : \e[32m |green   : \e[42m  |
#  |-------------------|--------------------|------------------|
#  |blink      : \e[5m |yellow     : \e[33m |yellow  : \e[43m  |
#  |-------------------|--------------------|------------------|
#  |reverse    : \e[7m |blue       : \e[34m |blue    : \e[44m  |
#  |-------------------|--------------------|------------------|
#  |invisible  : \e[8m |magenta    : \e[35m |magenta : \e[45m  |
#  |-------------------|--------------------|------------------|
#  |                   |cyan       : \e[36m |cyan    : \e[46m  |
#  |-------------------|--------------------|------------------|
#  |                   |white      : \e[37m |white   : \e[47m  |
#  |-------------------|--------------------|------------------|
#  |                   |default    : \e[39m |default : \e[49m  |
#  |-------------------|--------------------|------------------|
#
#  To reset the color codes:
#  - reset      : \e[0
#  Helpful control characters:
#  - backspace : \b
#
# Examples:
#  puts [ccolor::replace "<b>Blue on a <by>yellow background</>."]
#  puts [ccolor::replace "<u><gb>Underline</> and <v><r>reverse</>."]
# ########################################################################### #
namespace eval ccolor {
  variable reset   [binary format a4 \x1b\x5b\x30\x6d]
  # Helpful control characters #
  variable backspace [binary format a1 \x08]
  # Foreground #
  variable bold       [binary format a4 \x1b\x5b\x31\x6d]
  variable dim        [binary format a4 \x1b\x5b\x32\x6d]
  variable underlined [binary format a4 \x1b\x5b\x34\x6d]
  variable blink      [binary format a4 \x1b\x5b\x35\x6d]
  variable reverse    [binary format a4 \x1b\x5b\x37\x6d]
  variable invisible  [binary format a4 \x1b\x5b\x39\x6d]
  # Foreground colors #
  variable black   [binary format a5 \x1b\x5b\x33\x30\x6d]
  variable red     [binary format a5 \x1b\x5b\x33\x31\x6d]
  variable green   [binary format a5 \x1b\x5b\x33\x32\x6d]
  variable yellow  [binary format a5 \x1b\x5b\x33\x33\x6d]
  variable blue    [binary format a5 \x1b\x5b\x33\x34\x6d]
  variable magenta [binary format a5 \x1b\x5b\x33\x35\x6d]
  variable cyan    [binary format a5 \x1b\x5b\x33\x36\x6d]
  variable white   [binary format a5 \x1b\x5b\x33\x37\x6d]
  variable def     [binary format a5 \x1b\x5b\x33\x39\x6d]
  # Background colors #
  variable bblack   [binary format a5 \x1b\x5b\x34\x30\x6d]
  variable bred     [binary format a5 \x1b\x5b\x34\x31\x6d]
  variable bgreen   [binary format a5 \x1b\x5b\x34\x32\x6d]
  variable byellow  [binary format a5 \x1b\x5b\x34\x33\x6d]
  variable bblue    [binary format a5 \x1b\x5b\x34\x34\x6d]
  variable bmagenta [binary format a5 \x1b\x5b\x34\x35\x6d]
  variable bcyan    [binary format a5 \x1b\x5b\x34\x36\x6d]
  variable bwhite   [binary format a5 \x1b\x5b\x34\x37\x6d]
  variable bdef     [binary format a5 \x1b\x5b\x34\x39\x6d]

  # ########################################################################### #
  # Description:
  #  This procedure will parse the given input text and will replace all tags 
  #  with the corresponding color code. The tags are:
  #    |---------------------|------------------|--------------------------|
  #    |Effects              |Foreground Colors |Background Colors         |
  #    |---------------------|------------------|--------------------------|
  #    |<e> : bold (emphasis)|<k> : black       |<kb> : black background   |
  #    |---------------------|------------------|--------------------------|
  #    |<u> : underlined     |<r> : red         |<rb> : red background     |
  #    |---------------------|------------------|--------------------------|
  #    |<d> : dim            |<g> : green       |<gb> : green background   |
  #    |---------------------|------------------|--------------------------|
  #    |<f> : blink (flash)  |<y> : yellow      |<yb> : yellow background  |
  #    |---------------------|------------------|--------------------------|
  #    |<v> : reVerse        |<b> : blue        |<bb> : blue background    |
  #    |---------------------|------------------|--------------------------|
  #    |<i> : invisible      |<m> : magenta     |<mb> : magenta background |
  #    |---------------------|------------------|--------------------------|
  #    |                     |<c> : cyan        |<cb> : cyan background    |
  #    |---------------------|------------------|--------------------------|
  #    |                     |<w> : white       |<wb> : white background   |
  #    |---------------------|------------------|--------------------------|
  #    |                     |<d> : default     |<db> : default background |
  #    |---------------------|------------------|--------------------------|
  #
  #  To reset text printing to its normal behavior, use:
  #   </> : reset
  #  If you want to keep one of these tags unchanged in your text, please 
  #  escape them by pre-pending an additional '<' character. For example:
  #   "The <<r> tag sets the text color to <r>red</>"
  #   "The <</> tag resets printed text to its normal behavior."
  #  Additional helpful control tag:
  #   <bs> : backspace
  #  Examples of legal tagged text:
  #   "This text is <r>red</> and this one is <e><g>bold green</>."
  #   "<b>Blue on a <yb>yellow background</>."
  # ########################################################################### #
  proc replace {taggedText} {
    # Make sure the escaped tags do not get replaced #
    regsub -all -- "<<" $taggedText "<< " taggedText
    # Effects #
    regsub -all -- "<e>" $taggedText $ccolor::bold       taggedText
    regsub -all -- "<d>" $taggedText $ccolor::dim        taggedText
    regsub -all -- "<u>" $taggedText $ccolor::underlined taggedText
    regsub -all -- "<f>" $taggedText $ccolor::blink      taggedText
    regsub -all -- "<v>" $taggedText $ccolor::reverse    taggedText
    regsub -all -- "<i>" $taggedText $ccolor::invisible  taggedText
    # Foreground colors #
    regsub -all -- "<k>" $taggedText $ccolor::black      taggedText
    regsub -all -- "<r>" $taggedText $ccolor::red        taggedText
    regsub -all -- "<g>" $taggedText $ccolor::green      taggedText
    regsub -all -- "<y>" $taggedText $ccolor::yellow     taggedText
    regsub -all -- "<b>" $taggedText $ccolor::blue       taggedText
    regsub -all -- "<m>" $taggedText $ccolor::magenta    taggedText
    regsub -all -- "<c>" $taggedText $ccolor::cyan       taggedText
    regsub -all -- "<w>" $taggedText $ccolor::white      taggedText
    regsub -all -- "<d>" $taggedText $ccolor::def        taggedText
    # Background colors #
    regsub -all -- "<kb>" $taggedText $ccolor::bblack   taggedText
    regsub -all -- "<rb>" $taggedText $ccolor::bred     taggedText
    regsub -all -- "<gb>" $taggedText $ccolor::bgreen   taggedText
    regsub -all -- "<yb>" $taggedText $ccolor::byellow  taggedText
    regsub -all -- "<bb>" $taggedText $ccolor::bblue    taggedText
    regsub -all -- "<mb>" $taggedText $ccolor::bmagenta taggedText
    regsub -all -- "<cb>" $taggedText $ccolor::bcyan    taggedText
    regsub -all -- "<wb>" $taggedText $ccolor::bwhite   taggedText
    regsub -all -- "<db>" $taggedText $ccolor::bdef     taggedText
    # Reset #
    regsub -all -- "</>"  $taggedText $ccolor::reset taggedText
    # Other control characters #
    regsub -all -- "<bs>"  $taggedText $ccolor::backspace taggedText
    # Re-establish the escaped tags #
    regsub -all -- "<< " $taggedText "<<" taggedText
    # Un-escape them #
    regsub -all -- "<<e>"  $taggedText "<e>"  taggedText
    regsub -all -- "<<d>"  $taggedText "<d>"  taggedText
    regsub -all -- "<<u>"  $taggedText "<u>"  taggedText
    regsub -all -- "<<f>"  $taggedText "<f>"  taggedText
    regsub -all -- "<<v>"  $taggedText "<v>"  taggedText
    regsub -all -- "<<i>"  $taggedText "<i>"  taggedText
    regsub -all -- "<<k>"  $taggedText "<k>"  taggedText
    regsub -all -- "<<r>"  $taggedText "<r>"  taggedText
    regsub -all -- "<<g>"  $taggedText "<g>"  taggedText
    regsub -all -- "<<y>"  $taggedText "<y>"  taggedText
    regsub -all -- "<<b>"  $taggedText "<b>"  taggedText
    regsub -all -- "<<m>"  $taggedText "<m>"  taggedText
    regsub -all -- "<<c>"  $taggedText "<c>"  taggedText
    regsub -all -- "<<w>"  $taggedText "<w>"  taggedText
    regsub -all -- "<<d>"  $taggedText "<d>"  taggedText
    regsub -all -- "<<kb>" $taggedText "<kb>" taggedText
    regsub -all -- "<<rb>" $taggedText "<rb>" taggedText
    regsub -all -- "<<gb>" $taggedText "<gb>" taggedText
    regsub -all -- "<<yb>" $taggedText "<yb>" taggedText
    regsub -all -- "<<bb>" $taggedText "<bb>" taggedText
    regsub -all -- "<<mb>" $taggedText "<mb>" taggedText
    regsub -all -- "<<cb>" $taggedText "<cb>" taggedText
    regsub -all -- "<<wb>" $taggedText "<wb>" taggedText
    regsub -all -- "<<db>" $taggedText "<db>" taggedText
    regsub -all -- "<</>"  $taggedText "</>"  taggedText
    regsub -all -- "<<bs>" $taggedText "<bs>" taggedText
    # Return the changed text #
    return $taggedText
  }
}

Here's a short example on how to use it (using text retrieved from http://wiki.tcl.tk/2208 ):

tclsh8.5 [~]append tagged_text "The following is a list of categories (<e>not automatically updated, so there could be some missing</>) with short descriptions:\n"
tclsh8.5 [~]append tagged_text " * <b><u>Category Category</> - the meta category - covers the list of all categories.\n"
tclsh8.5 [~]append tagged_text " * <b><u>Category Uncategorized</> - the \"<d>anti-category</>\" - put on a page as a reminder that it hasn't really been categorized yet.\n"
tclsh8.5 [~]append tagged_text " * <b><u>Category 3D Graphics</> - pages relating to <g><v>3D graphical</> display of information\n"
tclsh8.5 [~]append tagged_text " * <b><u>Category Broken Links</> - used in connection with the <i>Broken Link Report\n"
tclsh8.5 [~]puts [ccolor::replace $tagged_text]

Or, if you want to use the namespace variables directly in a text string:

tclsh8.5 [~]puts " * ${ccolor::blue}Category AI${ccolor::reset} - pages relating to Artificial Intelligence"
tclsh8.5 [~]puts " * ${ccolor::blue}Category Critcl${ccolor::reset} - discussion of the Tcl runtime compile extension ${ccolor::bgreen}critcl${ccolor::reset}"