Advanced Bash-Scripting Guide: An in-depth exploration of the art of shell scripting | ||
---|---|---|
Prev | Chapter 33. Miscellany | Next |
ANSI [1] 定义了屏幕属性的转义序列集合,例如粗体文本,背景和前景颜色. DOS批处理文件(batch files) 一般使用ANSI的转义代码来控制色彩输出,Bash脚本也是这么做的.
例子 33-11. 一个 "彩色的" 地址资料库
1 #!/bin/bash 2 # ex30a.sh: ex30.sh的"彩色" 版本. 3 # 没有加工处理的地址资料库 4 5 6 clear # 清除屏幕. 7 8 echo -n " " 9 echo -e '\E[37;44m'"\033[1mContact List\033[0m" 10 # 白色为前景色,蓝色为背景色 11 echo; echo 12 echo -e "\033[1mChoose one of the following persons:\033[0m" 13 # 粗体 14 tput sgr0 15 echo "(Enter only the first letter of name.)" 16 echo 17 echo -en '\E[47;34m'"\033[1mE\033[0m" # 蓝色 18 tput sgr0 # 把色彩设置为"常规" 19 echo "vans, Roland" # "[E]vans, Roland" 20 echo -en '\E[47;35m'"\033[1mJ\033[0m" # 红紫色 21 tput sgr0 22 echo "ones, Mildred" 23 echo -en '\E[47;32m'"\033[1mS\033[0m" # 绿色 24 tput sgr0 25 echo "mith, Julie" 26 echo -en '\E[47;31m'"\033[1mZ\033[0m" # 红色 27 tput sgr0 28 echo "ane, Morris" 29 echo 30 31 read person 32 33 case "$person" in 34 # 注意变量被引起来了. 35 36 "E" | "e" ) 37 # 接受大小写的输入. 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 # 稍后为 Smith 和 Zane 增加信息. 61 62 * ) 63 # 默认选项Default option. 64 # 空的输入(直接按了回车) 也会匹配这儿. 65 echo 66 echo "Not yet in database." 67 ;; 68 69 esac 70 71 tput sgr0 # 把色彩重设为"常规". 72 73 echo 74 75 exit 0 |
例子 33-12. 画盒子
1 #!/bin/bash 2 # Draw-box.sh: 用ASCII字符画一个盒子. 3 4 # Stefano Palmeri编写,文档作者作了少量编辑. 5 # 征得作者同意在本书使用. 6 7 8 ###################################################################### 9 ### draw_box 函数的注释 ### 10 11 # "draw_box" 函数使用户可以在终端上画一个盒子. 12 # 13 # 14 # 用法: draw_box ROW COLUMN HEIGHT WIDTH [COLOR] 15 # ROW 和 COLUMN 定位要画的盒子的左上角. 16 # 17 # ROW 和 COLUMN 必须要大于0且小于目前终端的尺寸. 18 # 19 # HEIGHT 是盒子的行数,必须 > 0. 20 # HEIGHT + ROW 必须 <= 终端的高度. 21 # WIDTH 是盒子的列数,必须 > 0. 22 # WIDTH + COLUMN 必须 <= 终端的宽度. 23 # 24 # 例如: 如果你当前终端的尺寸是 20x80, 25 # draw_box 2 3 10 45 是合法的 26 # draw_box 2 3 19 45 的 HEIGHT 值是错的 (19+2 > 20) 27 # draw_box 2 3 18 78 的 WIDTH 值是错的 (78+3 > 80) 28 # 29 # COLOR 是盒子边框的颜色. 30 # 它是第5个参数,并且它是可选的. 31 # 0=黑色 1=红色 2=绿色 3=棕褐色 4=蓝色 5=紫色 6=青色 7=白色. 32 # 如果你传给这个函数错的参数, 33 #+ 它就会以代码65退出, 34 #+ 没有其他的信息打印到标准出错上. 35 # 36 # 在画盒子之前要清屏. 37 # 函数内不包含有清屏命令. 38 # 这使用户可以画多个盒子,甚至叠接多个盒子. 39 40 ### draw_box 函数注释结束 ### 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 # 如果参数小于4,退出. 56 exit $E_BADARGS 57 fi 58 59 # 搜寻参数中的非数字的字符. 60 # 能用其他更好的办法吗 (留给读者的练习?). 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 是需要的,因为因为边角的"+"是高和宽共有的部分. 66 BOX_WIDTH=`expr $4 - 1` # 67 T_ROWS=`tput lines` # 定义当前终端长和宽的尺寸, 68 T_COLS=`tput cols` # 69 70 if [ $1 -lt 1 ] || [ $1 -gt $T_ROWS ]; then # 如果参数是数字就开始检查有效性. 71 exit $E_BADARGS # 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 # 参数检查完毕. 85 86 plot_char(){ # 函数内的函数. 87 echo -e "\E[${1};${2}H"$3 88 } 89 90 echo -ne "\E[3${5}m" # 如果传递了盒子边框颜色参数,则设置它. 91 92 # start drawing the box 93 94 count=1 # 用plot_char函数画垂直线 95 for (( r=$1; count<=$BOX_HEIGHT; r++)); do # 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 # 用plot_char函数画水平线 108 for (( c=$2; count<=$BOX_WIDTH; c++)); do # 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 # 画盒子的角. 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" # 恢复最初的颜色. 126 127 P_ROWS=`expr $T_ROWS - 1` # 在终端的底部打印提示符. 128 129 echo -e "\E[${P_ROWS};1H" 130 } 131 132 133 # 现在, 让我们来画一个盒子. 134 clear # 清屏. 135 R=2 # 行 136 C=3 # 列 137 H=10 # 高 138 W=45 # 宽 139 col=1 # 颜色(红) 140 draw_box $R $C $H $W $col # 画盒子. 141 142 exit 0 143 144 # 练习: 145 # -------- 146 # 增加可以在盒子里打印文本的选项 |
最简单也可能是最有用的ANSI转义序列是加粗文本, \033[1m ... \033[0m. \033 触发转义序列, 而 "[1" 启用加粗属性, 而"[0" 表示切换回禁用加粗状态. "m"则表示终止一个转义序列.
bash$ echo -e "\033[1mThis is bold text.\033[0m" |
一种相似的转义序列可切换下划线效果 (在 rxvt 和 aterm 上).
bash$ echo -e "\033[4mThis is underlined text.\033[0m" |
echo使用-e选项可以启用转义序列. |
其他的转义序列可用于更改文本或/和背景色彩.
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 |
通常为淡色的前景色文本设置粗体效果是较好的. |
tput sgr0 把终端设置恢复为原样. 如果省略这一句会使后续在该终端的输出仍为蓝色.
因为tput sgr0 在某些环境下不能恢复终端设置, echo -ne \E[0m 会是更好的选择. |
可以在有色的背景上用下面的模板写有色彩的文本Use the following template for writing colored text on a colored background. echo -e '\E[COLOR1;COLOR2mSome text goes here.' "\E[" 开始转义序列. 分号分隔的数值"COLOR1" 和 "COLOR2" 指定前景色和背景色, 数值和色彩的对应参见下面的表格. (数值的顺序不是有关系的,因为前景色和背景色数值都落在不重叠的范围里.) "m"终止该转义序列, 然后文本以结束的转义指定的属性显示. 也要注意到用单引号引用了echo -e后面的余下命令序列. |
下表的数值是在 rxvt 终端运行的结果. 具体效果可能在其他的各种终端上不一样.
例子 33-13. 显示彩色文本
1 #!/bin/bash 2 # color-echo.sh: 用彩色来显示文本. 3 4 # 依照需要修改这个脚本. 5 # 这比手写彩色的代码更容易一些. 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" # 把文本属性重设回原来没有清屏前的 18 # 19 20 21 cecho () # Color-echo. 22 # 参数 $1 = 要显示的信息 23 # 参数 $2 = 颜色 24 { 25 local default_msg="No message passed." 26 # 不是非要一个本地变量. 27 28 message=${1:-$default_msg} # 默认的信息. 29 color=${2:-$black} # 如果没有指定,默认使用黑色. 30 31 echo -e "$color" 32 echo "$message" 33 Reset # 重设文本属性. 34 35 return 36 } 37 38 39 # 现在,让我们试试. 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 # 缺失 $color (色彩)参数. 48 cecho "\"Empty\" color passed (defaults to black)." "" 49 # 空的 $color (色彩)参数. 50 cecho 51 # $message(信息) 和 $color (色彩)参数都缺失. 52 cecho "" "" 53 # 空的 $message (信息)和 $color (色彩)参数. 54 # ---------------------------------------------------- 55 56 echo 57 58 exit 0 59 60 # 练习: 61 # --------- 62 # 1) 为'cecho ()'函数增加粗体的效果. 63 # 2) 增加可选的彩色背景. |
例子 33-14. "赛马" 游戏
1 #!/bin/bash 2 # horserace.sh: 非常简单的赛马模拟. 3 # 作者: Stefano Palmeri 4 # 已取得使用许可. 5 6 ################################################################ 7 # 脚本目的: 8 # 使用转义字符和终端颜色. 9 # 10 # 练习: 11 # 编辑脚本使其更具有随机性, 12 #+ 设置一个假的赌场 . . . 13 # 嗯 . . . 嗯 . . . 这个开始使我想起了一部电影 . . . 14 # 15 # 脚本给每匹马一个随机的障碍. 16 # 不均等会以障碍来计算 17 #+ 并且用一种欧洲风格表达出来. 18 # 例如: 机率(odds)=3.75 意味着如果你押1美元赢, 19 #+ 你可以赢得3.75美元. 20 # 21 # 脚本已经在GNU/Linux操作系统上测试过 OS, 22 #+ 测试终端有xterm 和 rxvt, 及 konsole. 23 # 测试机器有AMD 900 MHz 的处理器, 24 #+ 平均比赛时间是75秒. 25 # 在更快的计算机上比赛时间应该会更低. 26 # 所以, 如果你想有更多的悬念,重设USLEEP_ARG 变量的值. 27 # 28 # 由Stefano Palmeri编写. 29 ################################################################ 30 31 E_RUNERR=65 32 33 # 检查 md5sum 和 bc 是不是安装了. 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 # 更改下面的变量值可以使脚本执行的更慢. 46 # 它会作为usleep的参数 (man usleep) 47 #+ 并且它的单位是微秒 (500000微秒 = 半秒). 48 USLEEP_ARG=0 49 50 # 如果脚本接收到ctrl-c中断,清除临时目录, 恢复终端光标和颜色 51 # 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 # 参考调试的章节了解'trap'的更多解释 55 56 # 给脚本设置一个唯一(实际不是绝对唯一的)的临时目录名. 57 HORSE_RACE_TMP_DIR=$HOME/.horserace-`date +%s`-`head -c10 /dev/urandom | md5sum | head -c30` 58 59 # 创建临时目录,并切换到该目录下. 60 mkdir $HORSE_RACE_TMP_DIR 61 cd $HORSE_RACE_TMP_DIR 62 63 64 # 这个函数把光标移动到行为 $1 列为 $2 然后打印 $3. 65 # 例如: "move_and_echo 5 10 linux" 等同于 66 #+ "tput cup 4 9; echo linux", 但是用一个命令代替了两个. 67 # 注: "tput cup" 表示在终端左上角的 0 0 位置, 68 #+ echo 是在终端的左上角的 1 1 位置. 69 move_and_echo() { 70 echo -ne "\E[${1};${2}H""$3" 71 } 72 73 # 产生1-9之间伪随机数的函数. 74 random_1_9 () { 75 head -c10 /dev/urandom | md5sum | tr -d [a-z] | tr -d 0 | cut -c1 76 } 77 78 # 画马时模拟运动的两个函数. 79 draw_horse_one() { 80 echo -n " "//$MOVE_HORSE// 81 } 82 draw_horse_two(){ 83 echo -n " "\\\\$MOVE_HORSE\\\\ 84 } 85 86 87 # 取得当前的终端尺寸. 88 N_COLS=`tput cols` 89 N_LINES=`tput lines` 90 91 # 至少需要 20-行 X 80-列 的终端尺寸. 检查一下. 92 if [ $N_COLS -lt 80 ] || [ $N_LINES -lt 20 ]; then 93 echo "`basename $0` needs a 80-cols X 20-lines terminal." 94 echo "Your terminal is ${N_COLS}-cols X ${N_LINES}-lines." 95 exit $E_RUNERR 96 fi 97 98 99 # 开始画赛场. 100 101 # 需要一个80个字符的字符串,看下面的. 102 BLANK80=`seq -s "" 100 | head -c80` 103 104 clear 105 106 # 把前景和背景颜色设置成白色的. 107 echo -ne '\E[37;47m' 108 109 # 把光标移到终端的左上角. 110 tput cup 0 0 111 112 # 画六条白线. 113 for n in `seq 5`; do 114 echo $BLANK80 # 线是用80个字符组成的字符串. 115 done 116 117 # 把前景色设置成黑色. 118 echo -ne '\E[30m' 119 120 move_and_echo 3 1 "START 1" 121 move_and_echo 3 75 FINISH 122 move_and_echo 1 5 "|" 123 move_and_echo 1 80 "|" 124 move_and_echo 2 5 "|" 125 move_and_echo 2 80 "|" 126 move_and_echo 4 5 "| 2" 127 move_and_echo 4 80 "|" 128 move_and_echo 5 5 "V 3" 129 move_and_echo 5 80 "V" 130 131 # 把前景色设置成红色. 132 echo -ne '\E[31m' 133 134 # 一些ASCII艺术. 135 move_and_echo 1 8 "..@@@..@@@@@...@@@@@.@...@..@@@@..." 136 move_and_echo 2 8 ".@...@...@.......@...@...@.@......." 137 move_and_echo 3 8 ".@@@@@...@.......@...@@@@@.@@@@...." 138 move_and_echo 4 8 ".@...@...@.......@...@...@.@......." 139 move_and_echo 5 8 ".@...@...@.......@...@...@..@@@@..." 140 move_and_echo 1 43 "@@@@...@@@...@@@@..@@@@..@@@@." 141 move_and_echo 2 43 "@...@.@...@.@.....@.....@....." 142 move_and_echo 3 43 "@@@@..@@@@@.@.....@@@@...@@@.." 143 move_and_echo 4 43 "@..@..@...@.@.....@.........@." 144 move_and_echo 5 43 "@...@.@...@..@@@@..@@@@.@@@@.." 145 146 147 # 把前景和背景颜色设为绿色. 148 echo -ne '\E[32;42m' 149 150 # 画11行绿线. 151 tput cup 5 0 152 for n in `seq 11`; do 153 echo $BLANK80 154 done 155 156 # 把前景色设为黑色. 157 echo -ne '\E[30m' 158 tput cup 5 0 159 160 # 画栅栏. 161 echo "++++++++++++++++++++++++++++++++++++++\ 162 ++++++++++++++++++++++++++++++++++++++++++" 163 164 tput cup 15 0 165 echo "++++++++++++++++++++++++++++++++++++++\ 166 ++++++++++++++++++++++++++++++++++++++++++" 167 168 # 把前景和背景色设回白色. 169 echo -ne '\E[37;47m' 170 171 # 画3条白线. 172 for n in `seq 3`; do 173 echo $BLANK80 174 done 175 176 # 把前景色设为黑色. 177 echo -ne '\E[30m' 178 179 # 创建9个文件来保存障碍物. 180 for n in `seq 10 7 68`; do 181 touch $n 182 done 183 184 # 设置脚本要画的马的类型为第一种类型. 185 HORSE_TYPE=2 186 187 # 为每匹马创建位置文件和机率文件. 188 #+ 在这些文件里保存了该匹马当前的位置, 189 #+ 类型和机率. 190 for HN in `seq 9`; do 191 touch horse_${HN}_position 192 touch odds_${HN} 193 echo \-1 > horse_${HN}_position 194 echo $HORSE_TYPE >> horse_${HN}_position 195 # 给马定义随机的障碍物. 196 HANDICAP=`random_1_9` 197 # 检查random_1_9函数是否返回了有效值. 198 while ! echo $HANDICAP | grep [1-9] &> /dev/null; do 199 HANDICAP=`random_1_9` 200 done 201 # 给马定义最后的障碍的位置. 202 LHP=`expr $HANDICAP \* 7 + 3` 203 for FILE in `seq 10 7 $LHP`; do 204 echo $HN >> $FILE 205 done 206 207 # 计算机率. 208 case $HANDICAP in 209 1) ODDS=`echo $HANDICAP \* 0.25 + 1.25 | bc` 210 echo $ODDS > odds_${HN} 211 ;; 212 2 | 3) ODDS=`echo $HANDICAP \* 0.40 + 1.25 | bc` 213 echo $ODDS > odds_${HN} 214 ;; 215 4 | 5 | 6) ODDS=`echo $HANDICAP \* 0.55 + 1.25 | bc` 216 echo $ODDS > odds_${HN} 217 ;; 218 7 | 8) ODDS=`echo $HANDICAP \* 0.75 + 1.25 | bc` 219 echo $ODDS > odds_${HN} 220 ;; 221 9) ODDS=`echo $HANDICAP \* 0.90 + 1.25 | bc` 222 echo $ODDS > odds_${HN} 223 esac 224 225 226 done 227 228 229 # 打印机率. 230 print_odds() { 231 tput cup 6 0 232 echo -ne '\E[30;42m' 233 for HN in `seq 9`; do 234 echo "#$HN odds->" `cat odds_${HN}` 235 done 236 } 237 238 # 在起跑线上画马. 239 draw_horses() { 240 tput cup 6 0 241 echo -ne '\E[30;42m' 242 for HN in `seq 9`; do 243 echo /\\$HN/\\" " 244 done 245 } 246 247 print_odds 248 249 echo -ne '\E[47m' 250 # 等待回车按键开始赛马. 251 # 转义序列'\E[?25l'禁显了光标. 252 tput cup 17 0 253 echo -e '\E[?25l'Press [enter] key to start the race... 254 read -s 255 256 # 禁用了终端的常规显示功能. 257 # 这避免了赛跑时不小心按了按键键入显示字符而弄乱了屏幕. 258 # 259 stty -echo 260 261 # -------------------------------------------------------- 262 # 开始赛跑. 263 264 draw_horses 265 echo -ne '\E[37;47m' 266 move_and_echo 18 1 $BLANK80 267 echo -ne '\E[30m' 268 move_and_echo 18 1 Starting... 269 sleep 1 270 271 # 设置终点线的列数. 272 WINNING_POS=74 273 274 # 记录赛跑开始的时间. 275 START_TIME=`date +%s` 276 277 # COL 是由下面的"while"结构使用的. 278 COL=0 279 280 while [ $COL -lt $WINNING_POS ]; do 281 282 MOVE_HORSE=0 283 284 # 检查random_1_9函数是否返回了有效值. 285 while ! echo $MOVE_HORSE | grep [1-9] &> /dev/null; do 286 MOVE_HORSE=`random_1_9` 287 done 288 289 # 取得随机取得的马的类型和当前位置. 290 HORSE_TYPE=`cat horse_${MOVE_HORSE}_position | tail -1` 291 COL=$(expr `cat horse_${MOVE_HORSE}_position | head -1`) 292 293 ADD_POS=1 294 # 检查当前的位置是否是障碍物的位置. 295 if seq 10 7 68 | grep -w $COL &> /dev/null; then 296 if grep -w $MOVE_HORSE $COL &> /dev/null; then 297 ADD_POS=0 298 grep -v -w $MOVE_HORSE $COL > ${COL}_new 299 rm -f $COL 300 mv -f ${COL}_new $COL 301 else ADD_POS=1 302 fi 303 else ADD_POS=1 304 fi 305 COL=`expr $COL + $ADD_POS` 306 echo $COL > horse_${MOVE_HORSE}_position # 保存新位置. 307 308 # 选择要画的马的类型. 309 case $HORSE_TYPE in 310 1) HORSE_TYPE=2; DRAW_HORSE=draw_horse_two 311 ;; 312 2) HORSE_TYPE=1; DRAW_HORSE=draw_horse_one 313 esac 314 echo $HORSE_TYPE >> horse_${MOVE_HORSE}_position # 保存当前类型. 315 316 # 把前景色设为黑,背景色设为绿. 317 echo -ne '\E[30;42m' 318 319 # 把光标位置移到新的马的位置. 320 tput cup `expr $MOVE_HORSE + 5` `cat horse_${MOVE_HORSE}_position | head -1` 321 322 # 画马. 323 $DRAW_HORSE 324 usleep $USLEEP_ARG 325 326 # 当所有的马都越过15行的之后,再次打印机率. 327 touch fieldline15 328 if [ $COL = 15 ]; then 329 echo $MOVE_HORSE >> fieldline15 330 fi 331 if [ `wc -l fieldline15 | cut -f1 -d " "` = 9 ]; then 332 print_odds 333 : > fieldline15 334 fi 335 336 # 取得领头的马. 337 HIGHEST_POS=`cat *position | sort -n | tail -1` 338 339 # 把背景色重设为白色. 340 echo -ne '\E[47m' 341 tput cup 17 0 342 echo -n Current leader: `grep -w $HIGHEST_POS *position | cut -c7`" " 343 344 done 345 346 # 取得赛马结束的时间. 347 FINISH_TIME=`date +%s` 348 349 # 背景色设为绿色并且启用闪动的功能. 350 echo -ne '\E[30;42m' 351 echo -en '\E[5m' 352 353 # 使获胜的马闪动. 354 tput cup `expr $MOVE_HORSE + 5` `cat horse_${MOVE_HORSE}_position | head -1` 355 $DRAW_HORSE 356 357 # 禁用闪动文本. 358 echo -en '\E[25m' 359 360 # 把前景和背景色设为白色. 361 echo -ne '\E[37;47m' 362 move_and_echo 18 1 $BLANK80 363 364 # 前景色设为黑色. 365 echo -ne '\E[30m' 366 367 # 闪动获胜的马. 368 tput cup 17 0 369 echo -e "\E[5mWINNER: $MOVE_HORSE\E[25m"" Odds: `cat odds_${MOVE_HORSE}`"\ 370 " Race time: `expr $FINISH_TIME - $START_TIME` secs" 371 372 # 恢复光标和最初的颜色. 373 echo -en "\E[?25h" 374 echo -en "\E[0m" 375 376 # 恢复回显功能. 377 stty echo 378 379 # 删除赛跑的临时文件. 380 rm -rf $HORSE_RACE_TMP_DIR 381 382 tput cup 19 0 383 384 exit 0 |
参考 例子 A-22.
然而,有一个主要的问题,那就是ANSI 转义序列是不可移植的. 在一些终端运行的很好的代码可能在另外一些终端上可能运行地很糟糕. 在彩色脚本作者终端上运行的很好的脚本可能在另外一些终端上就产生不可阅读的输出了. 这给彩色脚本的用处大大打了个折扣,而很可能使这些技术变成一个暗机关或只是一个玩具而已. |
Moshe Jacobson的颜色工具(http://runslinux.net/projects.html#color)能相当容易地使用ANSI转义序列. 它用清晰和较有逻辑的语法来代替刚才讨论的难用的结构.
Henry/teikedvl 也同样开发了一个软件包来简化彩色脚本的一些操作 (http://scriptechocolor.sourceforge.net/).
[1] | 当然,ANSI是American National Standards Institute(美国国家标准组织)的缩写. 这个令人敬畏的组织建立和维护着许多技术和工业的标准. |