Advanced Bash-Scripting Guide: An in-depth exploration of the art of shell scripting | ||
---|---|---|
Prev | Chapter 34. Miscellany | Next |
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 34-9. 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 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 "ones, 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 Floppy 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 Jones" 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 34-10. 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 # Used in the "ABS Guide" with permission. 6 7 8 ###################################################################### 9 ### draw_box function doc ### 10 11 # The "draw_box" function lets the user 12 #+ draw a box into a terminal. 13 # 14 # Usage: draw_box ROW COLUMN HEIGHT WIDTH [COLOR] 15 # ROW and COLUMN represent the position 16 #+ of the upper left angle of the box you're going to draw. 17 # ROW and COLUMN must be greater than 0 18 #+ and less than current terminal dimension. 19 # HEIGHT is the number of rows of the box, and must be > 0. 20 # HEIGHT + ROW must be <= than current terminal height. 21 # WIDTH is the number of columns of the box and must be > 0. 22 # WIDTH + COLUMN must be <= than current terminal width. 23 # 24 # E.g.: If your terminal dimension is 20x80, 25 # draw_box 2 3 10 45 is good 26 # draw_box 2 3 19 45 has bad HEIGHT value (19+2 > 20) 27 # draw_box 2 3 18 78 has bad WIDTH value (78+3 > 80) 28 # 29 # COLOR is the color of the box frame. 30 # This is the 5th argument and is optional. 31 # 0=black 1=red 2=green 3=tan 4=blue 5=purple 6=cyan 7=white. 32 # If you pass the function bad arguments, 33 #+ it will just exit with code 65, 34 #+ and no messages will be printed on stderr. 35 # 36 # Clear the terminal before you start to draw a box. 37 # The clear command is not contained within the function. 38 # This allows the user to draw multiple boxes, even overlapping ones. 39 40 ### end of draw_box function doc ### 41 ###################################################################### 42 43 draw_box(){ 44 45 #=============# 46 HORZ="-" 47 VERT="|" 48 CORNER_CHAR="+" 49 50 MINARGS=4 51 E_BADARGS=65 52 #=============# 53 54 55 if [ $# -lt "$MINARGS" ]; then # If args are less than 4, exit. 56 exit $E_BADARGS 57 fi 58 59 # Looking for non digit chars in arguments. 60 # Probably it could be done better (exercise for the reader?). 61 if echo $@ | tr -d [:blank:] | tr -d [:digit:] | grep . &> /dev/null; then 62 exit $E_BADARGS 63 fi 64 65 BOX_HEIGHT=`expr $3 - 1` # -1 correction needed because angle char "+" is 66 BOX_WIDTH=`expr $4 - 1` #+ a part of both box height and width. 67 T_ROWS=`tput lines` # Define current terminal dimension 68 T_COLS=`tput cols` #+ in rows and columns. 69 70 if [ $1 -lt 1 ] || [ $1 -gt $T_ROWS ]; then # Start checking if arguments 71 exit $E_BADARGS #+ are correct. 72 fi 73 if [ $2 -lt 1 ] || [ $2 -gt $T_COLS ]; then 74 exit $E_BADARGS 75 fi 76 if [ `expr $1 + $BOX_HEIGHT + 1` -gt $T_ROWS ]; then 77 exit $E_BADARGS 78 fi 79 if [ `expr $2 + $BOX_WIDTH + 1` -gt $T_COLS ]; then 80 exit $E_BADARGS 81 fi 82 if [ $3 -lt 1 ] || [ $4 -lt 1 ]; then 83 exit $E_BADARGS 84 fi # End checking arguments. 85 86 plot_char(){ # Function within a function. 87 echo -e "\E[${1};${2}H"$3 88 } 89 90 echo -ne "\E[3${5}m" # Set box frame color, if defined. 91 92 # start drawing the box 93 94 count=1 # Draw vertical lines using 95 for (( r=$1; count<=$BOX_HEIGHT; r++)); do #+ plot_char function. 96 plot_char $r $2 $VERT 97 let count=count+1 98 done 99 100 count=1 101 c=`expr $2 + $BOX_WIDTH` 102 for (( r=$1; count<=$BOX_HEIGHT; r++)); do 103 plot_char $r $c $VERT 104 let count=count+1 105 done 106 107 count=1 # Draw horizontal lines using 108 for (( c=$2; count<=$BOX_WIDTH; c++)); do #+ plot_char function. 109 plot_char $1 $c $HORZ 110 let count=count+1 111 done 112 113 count=1 114 r=`expr $1 + $BOX_HEIGHT` 115 for (( c=$2; count<=$BOX_WIDTH; c++)); do 116 plot_char $r $c $HORZ 117 let count=count+1 118 done 119 120 plot_char $1 $2 $CORNER_CHAR # Draw box angles. 121 plot_char $1 `expr $2 + $BOX_WIDTH` + 122 plot_char `expr $1 + $BOX_HEIGHT` $2 + 123 plot_char `expr $1 + $BOX_HEIGHT` `expr $2 + $BOX_WIDTH` + 124 125 echo -ne "\E[0m" # Restore old colors. 126 127 P_ROWS=`expr $T_ROWS - 1` # Put the prompt at bottom of the terminal. 128 129 echo -e "\E[${P_ROWS};1H" 130 } 131 132 133 # Now, let's try drawing a box. 134 clear # Clear the terminal. 135 R=2 # Row 136 C=3 # Column 137 H=10 # Height 138 W=45 # Width 139 col=1 # Color (red) 140 draw_box $R $C $H $W $col # Draw the box. 141 142 exit 0 143 144 # Exercise: 145 # -------- 146 # 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. |
Use the following template for writing colored text on a colored background. echo -e '\E[COLOR1;COLOR2mSome text goes here.' The "\E[" begins the escape sequence. The semicolon-separated numbers "COLOR1" and "COLOR2" specify a foreground and a background color, according to the table below. (The order of the numbers does not matter, since the foreground and background numbers fall in non-overlapping ranges.) The "m" terminates the escape sequence, and the text begins immediately after that. Note also that single quotes enclose the remainder of the command sequence following the echo -e. |
The numbers in the following table work for an rxvt terminal. Results may vary for other terminal emulators.
Table 34-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 34-11. 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. |
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 greatly compromises the usefulness of "colorizing" scripts, and possibly relegates this technique to the status of a gimmick or even a "toy". |
Moshe Jacobson's color utility (http://runslinux.net/projects.html#color) 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.
[1] | ANSI is, of course, the acronym for the American National Standards Institute. |