Advanced Bash-Scripting Guide: An in-depth exploration of the art of shell scripting
Prev | Chapter 36. Miscellany | Next

# 36.5. "Colorizing" Scripts

The ANSI [1] escape sequences set screen attributes, such as bold text, and color of foreground and background. DOS batch files commonly used ANSI escape codes for color output, and so can Bash scripts.

Example 36-13. A "colorized" address database

       1 #!/bin/bash
       2 # ex30a.sh: "Colorized" version of ex30.sh.
       3 #            Crude address database
       4
       5
       6 clear                                   # Clear the screen.
       7
       8 echo -n "          "
       9 echo -e '\E[37;44m'"\033[1mContact List\033[0m"
      10                                         # White on blue background
      11 echo; echo
      12 echo -e "\033[1mChoose one of the following persons:\033[0m"
      13                                         # Bold
      14 tput sgr0                               # Reset attributes.
      15 echo "(Enter only the first letter of name.)"
      16 echo
      17 echo -en '\E[47;34m'"\033[1mE\033[0m"   # Blue
      18 tput sgr0                               # Reset colors to "normal."
      19 echo "vans, Roland"                     # "[E]vans, Roland"
      20 echo -en '\E[47;35m'"\033[1mJ\033[0m"   # Magenta
      21 tput sgr0
      22 echo "ambalaya, Mildred"
      23 echo -en '\E[47;32m'"\033[1mS\033[0m"   # Green
      24 tput sgr0
      25 echo "mith, Julie"
      26 echo -en '\E[47;31m'"\033[1mZ\033[0m"   # Red
      27 tput sgr0
      28 echo "ane, Morris"
      29 echo
      30
      31 read person
      32
      33 case "$person" in
      34 # Note variable is quoted.
      35
      36   "E" | "e" )
      37   # Accept upper or lowercase input.
      38   echo
      39   echo "Roland Evans"
      40   echo "4321 Flash Dr."
      41   echo "Hardscrabble, CO 80753"
      42   echo "(303) 734-9874"
      43   echo "(303) 734-9892 fax"
      44   echo "revans@zzy.net"
      45   echo "Business partner & old friend"
      46   ;;
      47
      48   "J" | "j" )
      49   echo
      50   echo "Mildred Jambalaya"
      51   echo "249 E. 7th St., Apt. 19"
      52   echo "New York, NY 10009"
      53   echo "(212) 533-2814"
      54   echo "(212) 533-9972 fax"
      55   echo "milliej@loisaida.com"
      56   echo "Girlfriend"
      57   echo "Birthday: Feb. 11"
      58   ;;
      59
      60 # Add info for Smith & Zane later.
      61
      62           * )
      63    # Default option.
      64    # Empty input (hitting RETURN) fits here, too.
      65    echo
      66    echo "Not yet in database."
      67   ;;
      68
      69 esac
      70
      71 tput sgr0                               # Reset colors to "normal."
      72
      73 echo
      74
      75 exit 0

Example 36-14. Drawing a box

       1 #!/bin/bash
       2 # Draw-box.sh: Drawing a box using ASCII characters.
       3
       4 # Script by Stefano Palmeri, with minor editing by document author.
       5 # Minor edits suggested by Jim Angstadt.
       6 # Used in the ABS Guide with permission.
       7
       8
       9 ######################################################################
      10 ###  draw_box function doc  ###
      11
      12 #  The "draw_box" function lets the user
      13 #+ draw a box in a terminal.
      14 #
      15 #  Usage: draw_box ROW COLUMN HEIGHT WIDTH [COLOR]
      16 #  ROW and COLUMN represent the position
      17 #+ of the upper left angle of the box you're going to draw.
      18 #  ROW and COLUMN must be greater than 0
      19 #+ and less than current terminal dimension.
      20 #  HEIGHT is the number of rows of the box, and must be > 0.
      21 #  HEIGHT + ROW must be <= than current terminal height.
      22 #  WIDTH is the number of columns of the box and must be > 0.
      23 #  WIDTH + COLUMN must be <= than current terminal width.
      24 #
      25 # E.g.: If your terminal dimension is 20x80,
      26 #  draw_box 2 3 10 45 is good
      27 #  draw_box 2 3 19 45 has bad HEIGHT value (19+2 > 20)
      28 #  draw_box 2 3 18 78 has bad WIDTH value (78+3 > 80)
      29 #
      30 #  COLOR is the color of the box frame.
      31 #  This is the 5th argument and is optional.
      32 #  0=black 1=red 2=green 3=tan 4=blue 5=purple 6=cyan 7=white.
      33 #  If you pass the function bad arguments,
      34 #+ it will just exit with code 65,
      35 #+ and no messages will be printed on stderr.
      36 #
      37 #  Clear the terminal before you start to draw a box.
      38 #  The clear command is not contained within the function.
      39 #  This allows the user to draw multiple boxes, even overlapping ones.
      40
      41 ###  end of draw_box function doc  ###
      42 ######################################################################
      43
      44 draw_box(){
      45
      46 #=============#
      47 HORZ="-"
      48 VERT="|"
      49 CORNER_CHAR="+"
      50
      51 MINARGS=4
      52 E_BADARGS=65
      53 #=============#
      54
      55
      56 if [ $# -lt "$MINARGS" ]; then          # If args are less than 4, exit.
      57     exit $E_BADARGS
      58 fi
      59
      60 # Looking for non digit chars in arguments.
      61 # Probably it could be done better (exercise for the reader?).
      62 if echo $@ | tr -d [:blank:] | tr -d [:digit:] | grep . &> /dev/null; then
      63    exit $E_BADARGS
      64 fi
      65
      66 BOX_HEIGHT=`expr $3 - 1`   #  -1 correction needed because angle char "+"
      67 BOX_WIDTH=`expr $4 - 1`    #+ is a part of both box height and width.
      68 T_ROWS=`tput lines`        #  Define current terminal dimension
      69 T_COLS=`tput cols`         #+ in rows and columns.
      70
      71 if [ $1 -lt 1 ] || [ $1 -gt $T_ROWS ]; then    #  Start checking if arguments
      72    exit $E_BADARGS                             #+ are correct.
      73 fi
      74 if [ $2 -lt 1 ] || [ $2 -gt $T_COLS ]; then
      75    exit $E_BADARGS
      76 fi
      77 if [ `expr $1 + $BOX_HEIGHT + 1` -gt $T_ROWS ]; then
      78    exit $E_BADARGS
      79 fi
      80 if [ `expr $2 + $BOX_WIDTH + 1` -gt $T_COLS ]; then
      81    exit $E_BADARGS
      82 fi
      83 if [ $3 -lt 1 ] || [ $4 -lt 1 ]; then
      84    exit $E_BADARGS
      85 fi                                 # End checking arguments.
      86
      87 plot_char(){                       # Function within a function.
      88    echo -e "\E[${1};${2}H"$3
      89 }
      90
      91 echo -ne "\E[3${5}m"               # Set box frame color, if defined.
      92
      93 # start drawing the box
      94
      95 count=1                                         #  Draw vertical lines using
      96 for (( r=$1; count<=$BOX_HEIGHT; r++)); do      #+ plot_char function.
      97   plot_char $r $2 $VERT
      98   let count=count+1
      99 done
     100
     101 count=1
     102 c=`expr $2 + $BOX_WIDTH`
     103 for (( r=$1; count<=$BOX_HEIGHT; r++)); do
     104   plot_char $r $c $VERT
     105   let count=count+1
     106 done
     107
     108 count=1                                        #  Draw horizontal lines using
     109 for (( c=$2; count<=$BOX_WIDTH; c++)); do      #+ plot_char function.
     110   plot_char $1 $c $HORZ
     111   let count=count+1
     112 done
     113
     114 count=1
     115 r=`expr $1 + $BOX_HEIGHT`
     116 for (( c=$2; count<=$BOX_WIDTH; c++)); do
     117   plot_char $r $c $HORZ
     118   let count=count+1
     119 done
     120
     121 plot_char $1 $2 $CORNER_CHAR                   # Draw box angles.
     122 plot_char $1 `expr $2 + $BOX_WIDTH` $CORNER_CHAR
     123 plot_char `expr $1 + $BOX_HEIGHT` $2 $CORNER_CHAR
     124 plot_char `expr $1 + $BOX_HEIGHT` `expr $2 + $BOX_WIDTH` $CORNER_CHAR
     125
     126 echo -ne "\E[0m"             #  Restore old colors.
     127
     128 P_ROWS=`expr $T_ROWS - 1`    #  Put the prompt at bottom of the terminal.
     129
     130 echo -e "\E[${P_ROWS};1H"
     131 }
     132
     133
     134 # Now, let's try drawing a box.
     135 clear                       # Clear the terminal.
     136 R=2      # Row
     137 C=3      # Column
     138 H=10     # Height
     139 W=45     # Width
     140 col=1    # Color (red)
     141 draw_box $R $C $H $W $col   # Draw the box.
     142
     143 exit 0
     144
     145 # Exercise:
     146 # --------
     147 # Add the option of printing text within the drawn box.

The simplest, and perhaps most useful ANSI escape sequence is bold text, \033[1m ... \033[0m. The \033 represents an escape, the "[1" turns on the bold attribute, while the "[0" switches it off. The "m" terminates each term of the escape sequence.

     bash$ echo -e "\033[1mThis is bold text.\033[0m"

A similar escape sequence switches on the underline attribute (on an rxvt and an aterm).

     bash$ echo -e "\033[4mThis is underlined text.\033[0m"

| With an echo, the `-e` option enables the escape sequences.

Other escape sequences change the text and/or background color.

     bash$ echo -e '\E[34;47mThis prints in blue.'; tput sgr0

     bash$ echo -e '\E[33;44m'"yellow text on blue background"; tput sgr0

     bash$ echo -e '\E[1;33;44m'"BOLD yellow text on blue background"; tput sgr0

| It's usually advisable to set the bold attribute for light-colored foreground text.

The tput sgr0 restores the terminal settings to normal. Omitting this lets all subsequent output from that particular terminal remain blue.

| Since tput sgr0 fails to restore terminal settings under certain circumstances, echo -ne \E[0m may be a better choice.

The numbers in the following table work for an rxvt terminal. Results may vary for other terminal emulators.

Table 36-1. Numbers representing colors in Escape Sequences

Color | Foreground | Background
--- | --- | ---
`black` | 30 | 40
`red` | 31 | 41
`green` | 32 | 42
`yellow` | 33 | 43
`blue` | 34 | 44
`magenta` | 35 | 45
`cyan` | 36 | 46
`white` | 37 | 47

Example 36-15. Echoing colored text

       1 #!/bin/bash
       2 # color-echo.sh: Echoing text messages in color.
       3
       4 # Modify this script for your own purposes.
       5 # It's easier than hand-coding color.
       6
       7 black='\E[30;47m'
       8 red='\E[31;47m'
       9 green='\E[32;47m'
      10 yellow='\E[33;47m'
      11 blue='\E[34;47m'
      12 magenta='\E[35;47m'
      13 cyan='\E[36;47m'
      14 white='\E[37;47m'
      15
      16
      17 alias Reset="tput sgr0"      #  Reset text attributes to normal
      18                              #+ without clearing screen.
      19
      20
      21 cecho ()                     # Color-echo.
      22                              # Argument $1 = message
      23                              # Argument $2 = color
      24 {
      25 local default_msg="No message passed."
      26                              # Doesn't really need to be a local variable.
      27
      28 message=${1:-$default_msg}   # Defaults to default message.
      29 color=${2:-$black}           # Defaults to black, if not specified.
      30
      31   echo -e "$color"
      32   echo "$message"
      33   Reset                      # Reset to normal.
      34
      35   return
      36 }
      37
      38
      39 # Now, let's try it out.
      40 # ----------------------------------------------------
      41 cecho "Feeling blue..." $blue
      42 cecho "Magenta looks more like purple." $magenta
      43 cecho "Green with envy." $green
      44 cecho "Seeing red?" $red
      45 cecho "Cyan, more familiarly known as aqua." $cyan
      46 cecho "No color passed (defaults to black)."
      47        # Missing $color argument.
      48 cecho "\"Empty\" color passed (defaults to black)." ""
      49        # Empty $color argument.
      50 cecho
      51        # Missing $message and $color arguments.
      52 cecho "" ""
      53        # Empty $message and $color arguments.
      54 # ----------------------------------------------------
      55
      56 echo
      57
      58 exit 0
      59
      60 # Exercises:
      61 # ---------
      62 # 1) Add the "bold" attribute to the 'cecho ()' function.
      63 # 2) Add options for colored backgrounds.

Example 36-16. A "horserace" game

       1 #!/bin/bash
       2 # horserace.sh: Very simple horserace simulation.
       3 # Author: Stefano Palmeri
       4 # Used with permission.
       5
       6 ################################################################
       7 #  Goals of the script:
       8 #  playing with escape sequences and terminal colors.
       9 #
      10 #  Exercise:
      11 #  Edit the script to make it run less randomly,
      12 #+ set up a fake betting shop . . .
      13 #  Um . . . um . . . it's starting to remind me of a movie . . .
      14 #
      15 #  The script gives each horse a random handicap.
      16 #  The odds are calculated upon horse handicap
      17 #+ and are expressed in European(?) style.
      18 #  E.g., odds=3.75 means that if you bet $1 and win,
      19 #+ you receive $3.75.
      20 #
      21 #  The script has been tested with a GNU/Linux OS,
      22 #+ using xterm and rxvt, and konsole.
      23 #  On a machine with an AMD 900 MHz processor,
      24 #+ the average race time is 75 seconds.
      25 #  On faster computers the race time would be lower.
      26 #  So, if you want more suspense, reset the USLEEP_ARG variable.
      27 #
      28 #  Script by Stefano Palmeri.
      29 ################################################################
      30
      31 E_RUNERR=65
      32
      33 # Check if md5sum and bc are installed.
      34 if ! which bc &> /dev/null; then
      35    echo bc is not installed.
      36    echo "Can\'t run . . . "
      37    exit $E_RUNERR
      38 fi
      39 if ! which md5sum &> /dev/null; then
      40    echo md5sum is not installed.
      41    echo "Can\'t run . . . "
      42    exit $E_RUNERR
      43 fi
      44
      45 #  Set the following variable to slow down script execution.
      46 #  It will be passed as the argument for usleep (man usleep)
      47 #+ and is expressed in microseconds (500000 = half a second).
      48 USLEEP_ARG=0
      49
      50 #  Clean up the temp directory, restore terminal cursor and
      51 #+ terminal colors -- if script interrupted by Ctl-C.
      52 trap 'echo -en "\E[?25h"; echo -en "\E[0m"; stty echo;\
      53 tput cup 20 0; rm -fr  $HORSE_RACE_TMP_DIR'  TERM EXIT
      54 #  See the chapter on debugging for an explanation of 'trap.'
      55
      56 # Set a unique (paranoid) name for the temp directory the script needs.
      57 HORSE_RACE_TMP_DIR=$HOME/.horserace-`date +%s`-`head -c10 /dev/urandom \
      58 | md5sum | head -c30`
      59
      60 # Create the temp directory and move right in.
      61 mkdir $HORSE_RACE_TMP_DIR
      62 cd $HORSE_RACE_TMP_DIR
      63
      64
      65 #  This function moves the cursor to line $1 column $2 and then prints $3.
      66 #  E.g.: "move_and_echo 5 10 linux" is equivalent to
      67 #+ "tput cup 4 9; echo linux", but with one command instead of two.
      68 #  Note: "tput cup" defines 0 0 the upper left angle of the terminal,
      69 #+ echo defines 1 1 the upper left angle of the terminal.
      70 move_and_echo() {
      71           echo -ne "\E[${1};${2}H""$3"
      72 }
      73
      74 # Function to generate a pseudo-random number between 1 and 9.
      75 random_1_9 ()
      76 {
      77     head -c10 /dev/urandom | md5sum | tr -d [a-z] | tr -d 0 | cut -c1
      78 }
      79
      80 #  Two functions that simulate "movement," when drawing the horses.
      81 draw_horse_one() {
      82                echo -n " "//$MOVE_HORSE//
      83 }
      84 draw_horse_two(){
      85               echo -n " "\\\\$MOVE_HORSE\\\\
      86 }
      87
      88
      89 # Define current terminal dimension.
      90 N_COLS=`tput cols`
      91 N_LINES=`tput lines`
      92
      93 # Need at least a 20-LINES X 80-COLUMNS terminal. Check it.
      94 if [ $N_COLS -lt 80 ] || [ $N_LINES -lt 20 ]; then
      95    echo "`basename $0` needs a 80-cols X 20-lines terminal."
      96    echo "Your terminal is ${N_COLS}-cols X ${N_LINES}-lines."
      97    exit $E_RUNERR
      98 fi
      99
     100
     101 # Start drawing the race field.
     102
     103 # Need a string of 80 chars. See below.
     104 BLANK80=`seq -s "" 100 | head -c80`
     105
     106 clear
     107
     108 # Set foreground and background colors to white.
     109 echo -ne '\E[37;47m'
     110
     111 # Move the cursor on the upper left angle of the terminal.
     112 tput cup 0 0
     113
     114 # Draw six white lines.
     115 for n in `seq 5`; do
     116       echo $BLANK80   # Use the 80 chars string to colorize the terminal.
     117 done
     118
     119 # Sets foreground color to black.
     120 echo -ne '\E[30m'
     121
     122 move_and_echo 3 1 "START  1"
     123 move_and_echo 3 75 FINISH
     124 move_and_echo 1 5 "|"
     125 move_and_echo 1 80 "|"
     126 move_and_echo 2 5 "|"
     127 move_and_echo 2 80 "|"
     128 move_and_echo 4 5 "|  2"
     129 move_and_echo 4 80 "|"
     130 move_and_echo 5 5 "V  3"
     131 move_and_echo 5 80 "V"
     132
     133 # Set foreground color to red.
     134 echo -ne '\E[31m'
     135
     136 # Some ASCII art.
     137 move_and_echo 1 8 "..@@@..@@@@@...@@@@@.@...@..@@@@..."
     138 move_and_echo 2 8 ".@...@...@.......@...@...@.@......."
     139 move_and_echo 3 8 ".@@@@@...@.......@...@@@@@.@@@@...."
     140 move_and_echo 4 8 ".@...@...@.......@...@...@.@......."
     141 move_and_echo 5 8 ".@...@...@.......@...@...@..@@@@..."
     142 move_and_echo 1 43 "@@@@...@@@...@@@@..@@@@..@@@@."
     143 move_and_echo 2 43 "@...@.@...@.@.....@.....@....."
     144 move_and_echo 3 43 "@@@@..@@@@@.@.....@@@@...@@@.."
     145 move_and_echo 4 43 "@..@..@...@.@.....@.........@."
     146 move_and_echo 5 43 "@...@.@...@..@@@@..@@@@.@@@@.."
     147
     148
     149 # Set foreground and background colors to green.
     150 echo -ne '\E[32;42m'
     151
     152 # Draw  eleven green lines.
     153 tput cup 5 0
     154 for n in `seq 11`; do
     155       echo $BLANK80
     156 done
     157
     158 # Set foreground color to black.
     159 echo -ne '\E[30m'
     160 tput cup 5 0
     161
     162 # Draw the fences.
     163 echo "++++++++++++++++++++++++++++++++++++++\
     164 ++++++++++++++++++++++++++++++++++++++++++"
     165
     166 tput cup 15 0
     167 echo "++++++++++++++++++++++++++++++++++++++\
     168 ++++++++++++++++++++++++++++++++++++++++++"
     169
     170 # Set foreground and background colors to white.
     171 echo -ne '\E[37;47m'
     172
     173 # Draw three white lines.
     174 for n in `seq 3`; do
     175       echo $BLANK80
     176 done
     177
     178 # Set foreground color to black.
     179 echo -ne '\E[30m'
     180
     181 # Create 9 files to stores handicaps.
     182 for n in `seq 10 7 68`; do
     183       touch $n
     184 done
     185
     186 # Set the first type of "horse" the script will draw.
     187 HORSE_TYPE=2
     188
     189 #  Create position-file and odds-file for every "horse".
     190 #+ In these files, store the current position of the horse,
     191 #+ the type and the odds.
     192 for HN in `seq 9`; do
     193       touch horse_${HN}_position
     194       touch odds_${HN}
     195       echo \-1 > horse_${HN}_position
     196       echo $HORSE_TYPE >>  horse_${HN}_position
     197       # Define a random handicap for horse.
     198        HANDICAP=`random_1_9`
     199       # Check if the random_1_9 function returned a good value.
     200       while ! echo $HANDICAP | grep [1-9] &> /dev/null; do
     201                 HANDICAP=`random_1_9`
     202       done
     203       # Define last handicap position for horse.
     204       LHP=`expr $HANDICAP \* 7 + 3`
     205       for FILE in `seq 10 7 $LHP`; do
     206             echo $HN >> $FILE
     207       done
     208
     209       # Calculate odds.
     210       case $HANDICAP in
     211               1) ODDS=`echo $HANDICAP \* 0.25 + 1.25 | bc`
     212                                  echo $ODDS > odds_${HN}
     213               ;;
     214               2 | 3) ODDS=`echo $HANDICAP \* 0.40 + 1.25 | bc`
     215                                        echo $ODDS > odds_${HN}
     216               ;;
     217               4 | 5 | 6) ODDS=`echo $HANDICAP \* 0.55 + 1.25 | bc`
     218                                              echo $ODDS > odds_${HN}
     219               ;;
     220               7 | 8) ODDS=`echo $HANDICAP \* 0.75 + 1.25 | bc`
     221                                        echo $ODDS > odds_${HN}
     222               ;;
     223               9) ODDS=`echo $HANDICAP \* 0.90 + 1.25 | bc`
     224                                   echo $ODDS > odds_${HN}
     225       esac
     226
     227
     228 done
     229
     230
     231 # Print odds.
     232 print_odds() {
     233 tput cup 6 0
     234 echo -ne '\E[30;42m'
     235 for HN in `seq 9`; do
     236       echo "#$HN odds->" `cat odds_${HN}`
     237 done
     238 }
     239
     240 # Draw the horses at starting line.
     241 draw_horses() {
     242 tput cup 6 0
     243 echo -ne '\E[30;42m'
     244 for HN in `seq 9`; do
     245       echo /\\$HN/\\"                               "
     246 done
     247 }
     248
     249 print_odds
     250
     251 echo -ne '\E[47m'
     252 # Wait for a enter key press to start the race.
     253 # The escape sequence '\E[?25l' disables the cursor.
     254 tput cup 17 0
     255 echo -e '\E[?25l'Press [enter] key to start the race...
     256 read -s
     257
     258 #  Disable normal echoing in the terminal.
     259 #  This avoids key presses that might "contaminate" the screen
     260 #+ during the race.
     261 stty -echo
     262
     263 # --------------------------------------------------------
     264 # Start the race.
     265
     266 draw_horses
     267 echo -ne '\E[37;47m'
     268 move_and_echo 18 1 $BLANK80
     269 echo -ne '\E[30m'
     270 move_and_echo 18 1 Starting...
     271 sleep 1
     272
     273 # Set the column of the finish line.
     274 WINNING_POS=74
     275
     276 # Define the time the race started.
     277 START_TIME=`date +%s`
     278
     279 # COL variable needed by following "while" construct.
     280 COL=0
     281
     282 while [ $COL -lt $WINNING_POS ]; do
     283
     284           MOVE_HORSE=0
     285
     286           # Check if the random_1_9 function has returned a good value.
     287           while ! echo $MOVE_HORSE | grep [1-9] &> /dev/null; do
     288                 MOVE_HORSE=`random_1_9`
     289           done
     290
     291           # Define old type and position of the "randomized horse".
     292           HORSE_TYPE=`cat  horse_${MOVE_HORSE}_position | tail -n 1`
     293           COL=$(expr `cat  horse_${MOVE_HORSE}_position | head -n 1`)
     294
     295           ADD_POS=1
     296           # Check if the current position is an handicap position.
     297           if seq 10 7 68 | grep -w $COL &> /dev/null; then
     298                 if grep -w $MOVE_HORSE $COL &> /dev/null; then
     299                       ADD_POS=0
     300                       grep -v -w  $MOVE_HORSE $COL > ${COL}_new
     301                       rm -f $COL
     302                       mv -f ${COL}_new $COL
     303                       else ADD_POS=1
     304                 fi
     305           else ADD_POS=1
     306           fi
     307           COL=`expr $COL + $ADD_POS`
     308           echo $COL >  horse_${MOVE_HORSE}_position  # Store new position.
     309
     310          # Choose the type of horse to draw.
     311           case $HORSE_TYPE in
     312                 1) HORSE_TYPE=2; DRAW_HORSE=draw_horse_two
     313                 ;;
     314                 2) HORSE_TYPE=1; DRAW_HORSE=draw_horse_one
     315           esac
     316           echo $HORSE_TYPE >>  horse_${MOVE_HORSE}_position
     317           # Store current type.
     318
     319           # Set foreground color to black and background to green.
     320           echo -ne '\E[30;42m'
     321
     322           # Move the cursor to new horse position.
     323           tput cup `expr $MOVE_HORSE + 5` \
     324 	  `cat  horse_${MOVE_HORSE}_position | head -n 1`
     325
     326           # Draw the horse.
     327           $DRAW_HORSE
     328            usleep $USLEEP_ARG
     329
     330            # When all horses have gone beyond field line 15, reprint odds.
     331            touch fieldline15
     332            if [ $COL = 15 ]; then
     333              echo $MOVE_HORSE >> fieldline15
     334            fi
     335            if [ `wc -l fieldline15 | cut -f1 -d " "` = 9 ]; then
     336                print_odds
     337                : > fieldline15
     338            fi
     339
     340           # Define the leading horse.
     341           HIGHEST_POS=`cat *position | sort -n | tail -1`
     342
     343           # Set background color to white.
     344           echo -ne '\E[47m'
     345           tput cup 17 0
     346           echo -n Current leader: `grep -w $HIGHEST_POS *position | cut -c7`\
     347 	  "                              "
     348
     349 done
     350
     351 # Define the time the race finished.
     352 FINISH_TIME=`date +%s`
     353
     354 # Set background color to green and enable blinking text.
     355 echo -ne '\E[30;42m'
     356 echo -en '\E[5m'
     357
     358 # Make the winning horse blink.
     359 tput cup `expr $MOVE_HORSE + 5` \
     360 `cat  horse_${MOVE_HORSE}_position | head -n 1`
     361 $DRAW_HORSE
     362
     363 # Disable blinking text.
     364 echo -en '\E[25m'
     365
     366 # Set foreground and background color to white.
     367 echo -ne '\E[37;47m'
     368 move_and_echo 18 1 $BLANK80
     369
     370 # Set foreground color to black.
     371 echo -ne '\E[30m'
     372
     373 # Make winner blink.
     374 tput cup 17 0
     375 echo -e "\E[5mWINNER: $MOVE_HORSE\E[25m""  Odds: `cat odds_${MOVE_HORSE}`"\
     376 "  Race time: `expr $FINISH_TIME - $START_TIME` secs"
     377
     378 # Restore cursor and old colors.
     379 echo -en "\E[?25h"
     380 echo -en "\E[0m"
     381
     382 # Restore echoing.
     383 stty echo
     384
     385 # Remove race temp directory.
     386 rm -rf $HORSE_RACE_TMP_DIR
     387
     388 tput cup 19 0
     389
     390 exit 0

See also Example A-21, Example A-44, Example A-52, and Example A-40.

There is, however, a major problem with all this. ANSI escape sequences are emphatically non-portable. What works fine on some terminal emulators (or the console) may work differently, or not at all, on others. A "colorized" script that looks stunning on the script author's machine may produce unreadable output on someone else's. This somewhat compromises the usefulness of colorizing scripts, and possibly relegates this technique to the status of a gimmick. Colorized scripts are probably inappropriate in a commercial setting, i.e., your supervisor might disapprove.

Alister's ansi-color utility (based on Moshe Jacobson's color utility considerably simplifies using ANSI escape sequences. It substitutes a clean and logical syntax for the clumsy constructs just discussed.

Henry/teikedvl has likewise created a utility (http://scriptechocolor.sourceforge.net/) to simplify creation of colorized scripts.

### Notes

[1] | ANSI is, of course, the acronym for the American National Standards Institute. This august body establishes and maintains various technical and industrial standards.

Prev | Home | Next
Recursion: a script calling itself | Up | Optimizations