فصل 36- گوناگون

‎36.5‎- اسکریپت‌های «رنگ‌افزایی»

رشته‌های escape در استاندارد ANSI ‎[1]‎ خصوصیات صفحه نمایش از قبیل متن پررنگ، و رنگ پس‌زمینه و متن را تنظیم می‌کنند. فایل‌های دسته‌ای DOS عموما از این کدهای escape برای رنگ خروجی استفاده می‌کردند، و همچنین اسکریپت‌های Bash نیز می‌توانند از آنها استفاده نمایند.

مثال ‎36-13‎. یک بانک اطلاعات آدرس «رنگی شده»

#!/bin/bash
#  ex30a.sh:    نگارش «رنگی شده» اسکریپت ‎ex30.sh
                                        #    بانک اطلاعات آدرس خام


clear                                   #    پاک کردن صفحه نمایش.

echo -n "          "
echo -e '\E[37;44m'"\033[1mContact List\033[0m"
                                        #    سفید روی پس‌زمینه آبی
echo; echo
echo -e "\033[1mChoose one of the following persons:\033[0m"
                                        #                    ضخیم
tput sgr0                               #   برگرداندن صفات اولیه.
echo "(Enter only the first letter of name.)"
echo
echo -en '\E[47;34m'"\033[1mE\033[0m"   #                     آبی
tput sgr0                               # تنظیم رنگ‌ها به «نرمال»‏.
echo "vans, Roland"                     # "[E]vans, Roland"
echo -en '\E[47;35m'"\033[1mJ\033[0m"   #                    بنفش
tput sgr0
echo "ambalaya, Mildred"
echo -en '\E[47;32m'"\033[1mS\033[0m"   #                     سبز
tput sgr0
echo "mith, Julie"
echo -en '\E[47;31m'"\033[1mZ\033[0m"   #                    قرمز
tput sgr0
echo "ane, Morris"
echo

read person

case "$person" in
#     توجه کنید، متغیر نقل‌قول می‌شود.

  "E" | "e" )
  # پذیرش ورودی با حرف بزرگ یا کوچک.
  echo
  echo "Roland Evans"
  echo "4321 Flash Dr."
  echo "Hardscrabble, CO 80753"
  echo "(303) 734-9874"
  echo "(303) 734-9892 fax"
  echo "revans@zzy.net"
  echo "Business partner & old friend"
  ;;

  "J" | "j" )
  echo
  echo "Mildred Jambalaya"
  echo "249 E. 7th St., Apt. 19"
  echo "New York, NY 10009"
  echo "(212) 533-2814"
  echo "(212) 533-9972 fax"
  echo "milliej@loisaida.com"
  echo "Girlfriend"
  echo "Birthday: Feb. 11"
  ;;

#           افزودن اطلاعات برای ‎Smith & Zane later‎

  * )
   #                             انتخاب قراردادی.  
   # ورودی خالی (زدن اینتر) نیز  اینجا مناسب است.
   echo
   echo "Not yet in database."
  ;;

esac

tput sgr0        # تنظیم دوباره رنگ‌ها به «نرمال»‏.

echo

exit 0

مثال ‎36-14‎. ترسیم یک کادر

#!/bin/bash
# Draw-box.sh: رسم یک کادر با استفاده از کاراکترهای اسکی.

#  اسکریپت نوشته ‎Stefano Palmeri‎ است که به طور جزیی 
#                          توسط نگارنده ویرایش شده.
#  ویرایش‌های جزیی توسط ‎Jim Angstadt‎ پیشنهاد گردیده.
# اسکریپت در این راهنما با مجوز استفاده گردیده است.

################################################################
###                               مستندات تابع ‎draw_box‎   ###

#  تابع ‎draw_box امکان رسم یک کادر در ترمینال را فراهم می‌کند.       
#
#     نحوه استفاده: ‎draw_box ROW COLUMN HEIGHT WIDTH [COLOR]‎ 
# ROW و COLUMN موقعیت گوشه چپ و بالای کادری را که می‌خواهید رسم      
#+                                        نمایید نشان می‌دهند.
# ROW و COLUMN باید ‎> 0‎ و کوچکتر از ابعاد ترمینال جاری باشند.
#      HEIGHT تعداد سطرهای کادر است و بایدبزرگتر از صفر باشد. 
# ‎HEIGHT + ROW‎ باید کوچکتر یا مساوی ارتفاع ترمینال جاری باشد.
#     WIDTH تعداد ستون‌های کادر است و باید بزرگتر از صفر باشد.
#  ‎WIDTH + COLUMN‎ باید کوچکتر یا مساوی عرض ترمینال جاری باشد.
#
#               یعنی: اگر ابعاد ترمینال شما ‎20x80‎ باشد، آنوقت
#                              ‎draw_box 2 3 10 45‎ مناسب است و
#  ‎draw_box 2 3 19 45‎ دارای ارتفاع نامناسب است، ‎(19+2 > 20)‎ و
#   ‎draw_box 2 3 18 78‎ دارای عرض نامناسب است، چون ‎(78+3 > 80)‎
#
#       COLOR رنگ قاب کادر است. این شناسه پنجم و اختیاری است.
# 0=black 1=red 2=green 3=tan 4=blue 5=purple 6=cyan 7=white.
# اگر شناسه‌های نامناسب به تابع بدهید، با یک کد 65 خارج می‌گردد
#+              و هیچ پیغام خطایی در stderr چاپ نخواهد گردید.
#
#            قبل از شروع به رسم کادر، صفحه نمایش را پاک کنید.
#    فرمان clear در داخل تابع گنجانده نشده است. این کار اجازه
#      می‌دهد کاربر چندین کادر، حتی دارای همپوشانی، رسم نماید.

###                         انتهای مستندات تابع ‎draw_box‎  ### 
################################################################

draw_box(){

#=============#
HORZ="-"
VERT="|"
CORNER_CHAR="+"

MINARGS=4
E_BADARGS=65
#=============#


if [ $# -lt "$MINARGS" ]; then       # اگر تعداد شناسه‌ها کمتر از ‎4‎ باشد، خروج.
    exit $E_BADARGS
fi

#     جستجوی کاراکترهایی در شناسه ها که رقم نیستند.
# شاید بتواند بهتر انجام بشود (تمرین برای خواننده).
if echo $@ | tr -d [:blank:] | tr -d [:digit:] | grep . &> /dev/null; then
   exit $E_BADARGS
fi

BOX_HEIGHT=`expr $3 - 1`      #  تصحیح ‎-1‎ لازم بود زیرا کاراکتر ‎"+"‎ گوشه
BOX_WIDTH=`expr $4 - 1`       #+      بخشی از هم طول و هم عرض کادر است.
T_ROWS=`tput lines`           # تعیین ابعاد جاری ترمینال به سطر و ستون.
T_COLS=`tput cols`  
      
if [ $1 -lt 1 ] || [ $1 -gt $T_ROWS ]; then    # شروع بررسی صحت شناسه‌ها
   exit $E_BADARGS                             
fi
if [ $2 -lt 1 ] || [ $2 -gt $T_COLS ]; then
   exit $E_BADARGS
fi
if [ `expr $1 + $BOX_HEIGHT + 1` -gt $T_ROWS ]; then
   exit $E_BADARGS
fi
if [ `expr $2 + $BOX_WIDTH + 1` -gt $T_COLS ]; then
   exit $E_BADARGS
fi
if [ $3 -lt 1 ] || [ $4 -lt 1 ]; then
   exit $E_BADARGS
fi                             #                  انتهای بررسی شناسه‌ها.

plot_char(){                   #                  تابع در درون یک تابع.
   echo -e "\E[${1};${2}H"$3
}

echo -ne "\E[3${5}m"           # تنظیم رنگ قاب کادر، اگر مشخص شده باشد.

                               #                     شروع رسم کردن کادر

count=1                   # رسم خطوط عمودی با استفاده از تابع plot_char
for (( r=$1; count<=$BOX_HEIGHT; r++)); do      
  plot_char $r $2 $VERT
  let count=count+1
done 

count=1
c=`expr $2 + $BOX_WIDTH`
for (( r=$1; count<=$BOX_HEIGHT; r++)); do
  plot_char $r $c $VERT
  let count=count+1
done 

count=1                    #  رسم خطوط افقی با استفاده از تابع plot_char
for (( c=$2; count<=$BOX_WIDTH; c++)); do
  plot_char $1 $c $HORZ
  let count=count+1
done 

count=1
r=`expr $1 + $BOX_HEIGHT`
for (( c=$2; count<=$BOX_WIDTH; c++)); do
  plot_char $r $c $HORZ
  let count=count+1
done 

plot_char $1 $2 $CORNER_CHAR                   #  رسم کردن گوشه‌های کادر.
plot_char $1 `expr $2 + $BOX_WIDTH` $CORNER_CHAR
plot_char `expr $1 + $BOX_HEIGHT` $2 $CORNER_CHAR
plot_char `expr $1 + $BOX_HEIGHT` `expr $2 + $BOX_WIDTH` $CORNER_CHAR

echo -ne "\E[0m"                               #   بازیابی رنگ‌های قدیمی.

P_ROWS=`expr $T_ROWS - 1`             # قرار دادن اعلان در پایین ترمینال.

echo -e "\E[${P_ROWS};1H"
}      

#        اکنون اجازه بدهید کشیدن یک کادر را امتحان کنیم.
clear                              #   پاک کردن ترمینال.
R=2          #        سطر
C=3          #       ستون
H=10         #     ارتفاع
W=45         #        عرض
col=1        # رنگ (قرمز)‏
draw_box $R $C $H $W $col          #         ترسیم کادر.

exit 0

#                          تمرین:
#                        ----------
# امکان چاپ کردن متن در داخل کادر رسم شده را اضافه کنید.

ساده‌ترین، و شاید مفیدترین رشته escape در ANSI متن ضخیم، یعنی ‎\033[1m ... \033[0m‎ است. کد ‎\033‎ نماینده یک escape است، و «‎[1‎» صفت ضخیم را روشن می‌کند، در حالیکه «‎[0‎» آن را به وضعیت خاموش تبدیل می‌کند. کاراکتر «m» هر عبارت رشته escape را خاتمه می‌دهد.

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

یک رشته escape مشابه نیز صفت خط زیر را روشن می‌کند (در یک rxvt و یک aterm).

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


با یک echo، گزینه ‎-e‎ رشته‌های escape را فعال می‌کند.

رشته‌های escape دیگری رنگ متن و/یا پس‌زمینه را تغییر می‌دهند.

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


معمولاً تنظیم صفت bold برای متن پیش‌زمینه با رنگ روشن، قابل توصیه است.

‎tput sgr0‎ تنظیمات عادی ترمینال را بازیابی می‌کند. از قلم انداختن آن اجازه می‌دهد تمام خروجی‌های بعدی آن ترمینال بخصوص به رنگ آبی باقی بمانند.


‎tput sgr0‎ تحت شرایط خاصی در بازیابی تنظیمات ترمینال ناموفق می‌شود، ‎echo -ne \E[0m‎ می‌تواند انتخاب مناسب‌تری باشد.

اعداد در جدول زیر برای یک ترمینال rxvt کار می‌کنند. برای سایر شبیه‌سازهای ترمینال نتایج می‌تواند تغییر نماید.

جدول ‎36-1‎. اعداد نشان‌دهنده رنگ‌ها در رشته‌های Escape

رنگپیش‌زمینهپس‌زمینه
black 30 40
red 31 41
green 32 42
yellow 33 43
blue 34 44
magenta 35 45
cyan 36 46
white 37 47

مثال ‎36-15‎. نمایش متن رنگی

#!/bin/bash
#  color-echo.sh:      نمایش پیغام‌های متنی رنگی.

# این اسکریپت را طبق نیازهای خودتان ویرایش کنید.
#                آسان‌تر از کدگذاری دستی رنگ است.

black='\E[30;47m'
red='\E[31;47m'
green='\E[32;47m'
yellow='\E[33;47m'
blue='\E[34;47m'
magenta='\E[35;47m'
cyan='\E[36;47m'
white='\E[37;47m'


alias Reset="tput sgr0"      #        تنظیم دوباره صفات متن به نرمال
                             #+            بدون پاک کردن صفحه نمایش.


cecho ()                     #                       تابع echo رنگی.
                             #                      شناسه ‎$1‎ = پیغام
                             #                        شناسه ‎$2‎ = رنگ
{
local default_msg="No message passed."
                             #در واقع نیازی نیست که متغیر محلی باشد.

message=${1:-$default_msg}   #           تنظیم پیغام به مورد پیش‌فرض.
color=${2:-$black}           # اگر رنگ تعیین نشود، سیاه پیش‌فرض باشد.

  echo -e "$color"
  echo "$message"
  Reset                      #                 بازگردانی صفات نرمال.

  return
}  


#        اکنون، بیایید آن را امتحان کنیم.
# -------------------------------------------------
cecho "Feeling blue..." $blue
cecho "Magenta looks more like purple." $magenta
cecho "Green with envy." $green
cecho "Seeing red?" $red
cecho "Cyan, more familiarly known as aqua." $cyan
cecho "No color passed (defaults to black)."
       #            در غیبت شناسه ‎$color‎.
cecho "\"Empty\" color passed (defaults to black)." ""
       #                شناسه ‎$color‎ تهی.
cecho
       # غیبت شناسه‌های ‎$message‎ و ‎$color‎.
cecho "" ""
       #  شناسه‌های تهی ‎$message‎ و ‎$color‎.
# -------------------------------------------------

echo

exit 0

#                      تمرین‌ها:
#              -------------------
#   ‎(1‎ صفت bold را به تابع ‎cecho ()‎ اضافه کنید.
# ‎(2‎ گزینه‌هایی برای پس‌زمینه‌های رنگی اضافه کنید.

مثال ‎36-16‎. یک بازی «horserace»

#!/bin/bash
# horserace.sh:    یک شبیه‌سازی بسیار ساده مسابقه اسب‌ها.
#                              نویسنده: ‎Stefano Palmeri‎
#                                  استفاده شده با مجوز.

#############################################################
#                                        اهداف اسکریپت:
#        کار کردن با رشته‌های escape و رنگ‌ها در ترمینال.
#
#                                                تمرین:
#   اسکریپت را ویرایش کنید تا اتفاقی بودن آن کمتر بشود،
#+                یک دکان شرط بندی جعلی برپا کنید . . .     
#    هه . . . هه . . . نمایشی را به یاد من می‌آورد . . .
#
#             اسکریپت به هر اسب یک امتیاز تصادفی می‌دهد.
#  مزیت‌های شرط‌بندی بر اساس امتیاز اسب محاسبه می‌شود و با
#+                      یک سبکِ اروپایی(؟)‎ بیان می‌گردند.
#   به عنوان مثال، ‎odds=3.75‎ یعنی که اگر شما یک دلار شرط
#+        ببندید و برنده بشوید، ‎3.75‎ دلار دریافت می‌کنید.
# 
#    اسکریپت در یک سیستم عامل گنو-لینوکس، با استفاده از
#+                xterm و rxvt، و کنسول تست گردیده است.
#    روی ماشینی با یک پردازشگر ‎AMD 900 MHz‎ میانگین زمان
#+                                 مسابقه ‎75‎ ثانیه است.   
#    روی کامپیوترهای سریع‌تر زمان مسابقه کمتر خواهد بود.
#اگر تعلیق بیشتری می‌خواهید متغیر USLEEP_ARG تغییر دهید.
#
#                    اسکریپت نوشته ‎Stefano Palmeri‎ است.
#############################################################

E_RUNERR=65

#                      بررسی برای اینکه md5sum و bc نصب شده باشند
if ! which bc &> /dev/null; then
   echo bc is not installed.  
   echo "Can\'t run . . . "
   exit $E_RUNERR
fi
if ! which md5sum &> /dev/null; then
   echo md5sum is not installed.  
   echo "Can\'t run . . . "
   exit $E_RUNERR
fi

#          برای کندتر نمودن اجرای اسکریپت متغیر زیر را تنظیم کنید.
#     این متغیر که به عنوان شناسه به usleep‏ ‎(man usleep)‎ عبور داده  
#+     می‌شود، بر حسب میکرو ثانیه بیان می‌گردد (‎500000‎ = نیم ثانیه).
USLEEP_ARG=0  

#    پاکسازی دایرکتوری موقت، بازیابی مکان نما و رنگ‌های ترمینال، در
#+                      صورتی‌که اسکریپت به وسیله ‎Ctl-C‎ متوقف گردد.
trap 'echo -en "\E[?25h"; echo -en "\E[0m"; stty echo;\
tput cup 20 0; rm -fr  $HORSE_RACE_TMP_DIR'  TERM EXIT
#     برای توضیح در باره ‎trap‎، فصل مربوط به اشکالزدایی را بخوانید.

# تنظیم نام بی‌همتا (بدگمانی) جهت دایرکتوری موقت مورد نیاز اسکریپت.
HORSE_RACE_TMP_DIR=$HOME/.horserace-`date +%s`-`head -c10 /dev/urandom \
| md5sum | head -c30`

#               ایجاد دایرکتوری موقت و تعویض دایرکتوری جاری به آن.
mkdir $HORSE_RACE_TMP_DIR
cd $HORSE_RACE_TMP_DIR


# این تابع اشاره‌گر را به سطر ‎$1‎ و ستون ‎$2‎ جابجا نموده و سپس ‎$3‎ را
# چاپ می‌کند.  به عنوان نمونه: «‎move_and_echo 5 10 linux‎» معادل با
#+«‎tput cup 4 9; echo linux‎»، امابه جای دو فرمان با یک دستور است.
#نکته: «‎tput cup‎» محل ‎0 0‎ را گوشه سمت چپ بالای ترمینال تعیین می‌کند
#+    و echo نقطه ‎1 1‎ را گوشه سمت چپ بالای ترمینال را تعیین می‌کند.
move_and_echo() {
          echo -ne "\E[${1};${2}H""$3" 
}

#                  تابعی برای تولید یک عدد شبه تصادفی بین ‎1‎ تا ‎9‎. 
random_1_9 ()
{
    head -c10 /dev/urandom | md5sum | tr -d [a-z] | tr -d 0 | cut -c1 
}

#           دو تابع که موقع ترسیم اسب‌ها، حرکت را شبیه‌سازی می‌کنند. 
draw_horse_one() {
               echo -n " "//$MOVE_HORSE//
}
draw_horse_two(){
              echo -n " "\\\\$MOVE_HORSE\\\\ 
}   

# مترجم: توابع فوق دو نوع اسب ترسیم می‌کنند. در نوع اول پاهای اسب
عقب است و در نوع دوم پاهای اسب جلو است که با اجرای متناوب آنها # 
حرکت پاهای اسب به جلو و عقب شبیه‌سازی می‌گردد.                   # 
#                                   تعیین اندازه‌های ترمینال جاری.
N_COLS=`tput cols` 
N_LINES=`tput lines`

#ترمینالی با حداقل ۲۰ سطر و حداقل ۸۰ ستون لازم است، کنترل وجود آن.
if [ $N_COLS -lt 80 ] || [ $N_LINES -lt 20 ]; then
   echo "`basename $0` needs a 80-cols X 20-lines terminal."
   echo "Your terminal is ${N_COLS}-cols X ${N_LINES}-lines."
   exit $E_RUNERR
fi


#                                        شروع ترسیم میدان مسابقه.

#               به یک رشته ۸۰ کاراکتری نیاز است. پایین را ببینید.
BLANK80=`seq -s "" 100 | head -c80`

clear

#                           تنظیم رنگ پیش‌زمینه و پس‌زمینه به سفید.
echo -ne '\E[37;47m'

#                حرکت دادن مکان‌نما به گوشه سمت چپ و بالای ترمینال.
tput cup 0 0 

#                                               رسم نمودن شش سطر.
for n in `seq 5`; do
      echo $BLANK80  # استفاده از رشته ۸۰ کاراکتری برای رنگ‌آمیزی.
done

#                                تنظیم کردن رنگ پیش‌زمینه به سیاه. 
echo -ne '\E[30m'

move_and_echo 3 1 "START  1"            
move_and_echo 3 75 FINISH
move_and_echo 1 5 "|"
move_and_echo 1 80 "|"
move_and_echo 2 5 "|"
move_and_echo 2 80 "|"
move_and_echo 4 5 "|  2"
move_and_echo 4 80 "|"
move_and_echo 5 5 "V  3"
move_and_echo 5 80 "V"

#         تنظیم رنگ پیش‌زمینه به قرمز. 
echo -ne '\E[31m'

#              مقداری هنر نمایی اسکی.
move_and_echo 1 8 "..@@@..@@@@@...@@@@@.@...@..@@@@..."
move_and_echo 2 8 ".@...@...@.......@...@...@.@......."
move_and_echo 3 8 ".@@@@@...@.......@...@@@@@.@@@@...."
move_and_echo 4 8 ".@...@...@.......@...@...@.@......."
move_and_echo 5 8 ".@...@...@.......@...@...@..@@@@..."
move_and_echo 1 43 "@@@@...@@@...@@@@..@@@@..@@@@."
move_and_echo 2 43 "@...@.@...@.@.....@.....@....."
move_and_echo 3 43 "@@@@..@@@@@.@.....@@@@...@@@.."
move_and_echo 4 43 "@..@..@...@.@.....@.........@."
move_and_echo 5 43 "@...@.@...@..@@@@..@@@@.@@@@.."


# تنظیم رنگ پیش‌زمینه و پس‌زمینه به سبز.
echo -ne '\E[32;42m'

#                 ترسیم یازده سطر سبز.
tput cup 5 0
for n in `seq 11`; do
      echo $BLANK80
done

#          تنظیم رنگ پیش‌زمینه به مشکی. 
echo -ne '\E[30m'
tput cup 5 0

#                     رسم کردن حصارها. 
echo "++++++++++++++++++++++++++++++++++++++\
++++++++++++++++++++++++++++++++++++++++++"

tput cup 15 0
echo "++++++++++++++++++++++++++++++++++++++\
++++++++++++++++++++++++++++++++++++++++++"

#تنظیم رنگ پیش‌زمینه و پس‌زمینه به سفید.
echo -ne '\E[37;47m'

#                رسم کردن سه سطر سفید.
for n in `seq 3`; do
      echo $BLANK80
done

#          تنظیم رنگ پیش‌زمینه به سیاه.
echo -ne '\E[30m'

#  ایجاد ۹ فایل برای نگهداری امتیازها.
for n in `seq 10 7 68`; do
      touch $n
done  

#      تنظیم نوع اول اسبی که اسکریپت رسم خواهد نمود.
HORSE_TYPE=2

#   ایجاد فایل موقعیت و فایل مزیت‌ها برای هر «horse».
#+ در این فایل‌ها، موقعیت جاری، نوع و مزیت‌های شرط‌بندی
#+                             اسب‌ها نگهداری می‌گردد.
for HN in `seq 9`; do
      touch horse_${HN}_position
      touch odds_${HN}
      echo \-1 > horse_${HN}_position
      echo $HORSE_TYPE >>  horse_${HN}_position
      #                    تعیین یک امتیاز تصادفی برای اسب.
       HANDICAP=`random_1_9`
      # کنترل آنکه تابع ‎random_1_9‎ مقدار مناسبی برگشت داده.
      while ! echo $HANDICAP | grep [1-9] &> /dev/null; do
                HANDICAP=`random_1_9`
      done
      #             مشخص کردن آخرین امتیاز موقعیت برای اسب. 
      LHP=`expr $HANDICAP \* 7 + 3`
      for FILE in `seq 10 7 $LHP`; do
            echo $HN >> $FILE
      done   
     
      # محاسبه مزیت‌ها.
      case $HANDICAP in 
              1) ODDS=`echo $HANDICAP \* 0.25 + 1.25 | bc`
                                 echo $ODDS > odds_${HN}
              ;;
              2 | 3) ODDS=`echo $HANDICAP \* 0.40 + 1.25 | bc`
                                       echo $ODDS > odds_${HN}
              ;;
              4 | 5 | 6) ODDS=`echo $HANDICAP \* 0.55 + 1.25 | bc`
                                             echo $ODDS > odds_${HN}
              ;; 
              7 | 8) ODDS=`echo $HANDICAP \* 0.75 + 1.25 | bc`
                                       echo $ODDS > odds_${HN}
              ;; 
              9) ODDS=`echo $HANDICAP \* 0.90 + 1.25 | bc`
                                  echo $ODDS > odds_${HN}
      esac


done


#             چاپ مزیت‌ها.
print_odds() {
tput cup 6 0
echo -ne '\E[30;42m'
for HN in `seq 9`; do
      echo "#$HN odds->" `cat odds_${HN}`
done
}

# ترسیم اسب‌ها در خط شروع.
draw_horses() {
tput cup 6 0
echo -ne '\E[30;42m'
for HN in `seq 9`; do
      echo /\\$HN/\\"                               "
done
}

print_odds

echo -ne '\E[47m'
#                انتظار برای زدن کلیدی جهت شروع مسابقه.
#      ‎'\E[?25l'‎ رشته escape غیر فعال کردن مکان‌نما است.
tput cup 17 0
echo -e '\E[?25l'Press [enter] key to start the race...
read -s

#  غیر فعال سازی echo نمودن عادی در ترمینال. این کار از
#  آلوده شدن صفحه نمایش در مدت زمان انجام مسابقه در اثر
#+                           ضربه‌کلیدها پیش‌گیری می‌کند.  
stty -echo

# -----------------------------------------------------
#                        آغاز مسابقه.

draw_horses
echo -ne '\E[37;47m'
move_and_echo 18 1 $BLANK80
echo -ne '\E[30m'
move_and_echo 18 1 Starting...
sleep 1

#                             تنظیم کردن ستون خط پایان.
WINNING_POS=74

#               مشخص کردن زمانی که مسابقه شروع شده است.
START_TIME=`date +%s`

# متغیر COL برای ساختار «while» در ادامه مورد نیاز است.
COL=0    

while [ $COL -lt $WINNING_POS ]; do
                   
          MOVE_HORSE=0     
          
          #بررسی که ‎random_1_9‎ مقدار مناسبی برگشت داده.
          while ! echo $MOVE_HORSE | grep [1-9] &> /dev/null; do
                MOVE_HORSE=`random_1_9`
          done
          
          # تعیین موقعیت و نوع قبلی برای یک اسب اتفاقی‎.
          HORSE_TYPE=`cat  horse_${MOVE_HORSE}_position | tail -n 1`
          COL=$(expr `cat  horse_${MOVE_HORSE}_position | head -n 1`)
          
          ADD_POS=1
          #  بررسی آنکه موقعیت جاری، یک موضع ممتاز است. 
          if seq 10 7 68 | grep -w $COL &> /dev/null; then
                if grep -w $MOVE_HORSE $COL &> /dev/null; then
                      ADD_POS=0
                      grep -v -w  $MOVE_HORSE $COL > ${COL}_new
                      rm -f $COL
                      mv -f ${COL}_new $COL
                      else ADD_POS=1
                fi 
          else ADD_POS=1
          fi
          COL=`expr $COL + $ADD_POS`
          #                            ذخیره موضع جدید.
          echo $COL >  horse_${MOVE_HORSE}_position  
                            
          #                انتخاب نوع اسب جهت ترسیم آن.       
          case $HORSE_TYPE in 
                1) HORSE_TYPE=2; DRAW_HORSE=draw_horse_two
                ;;
                2) HORSE_TYPE=1; DRAW_HORSE=draw_horse_one 
          esac       
          echo $HORSE_TYPE >>  horse_${MOVE_HORSE}_position
          #                         ذخیره نوع جاری اسب.
         
          #تنظیم رنگ پیش‌زمینه به سیاه و پس‌زمینه به سبز.
          echo -ne '\E[30;42m'
          
          #       حرکت دادن مکان‌نما به موقعیت جدید اسب.
          tput cup `expr $MOVE_HORSE + 5` \
	  `cat  horse_${MOVE_HORSE}_position | head -n 1` 
          
          #                               رسم کردن اسب.
          $DRAW_HORSE
           usleep $USLEEP_ARG
          
           # چاپ دوباره مزیت‌ها، وقتی همه اسب‌ها به خط ۱۵ میدان رسیدند.
           touch fieldline15
           if [ $COL = 15 ]; then
             echo $MOVE_HORSE >> fieldline15  
           fi
           if [ `wc -l fieldline15 | cut -f1 -d " "` = 9 ]; then
               print_odds
               : > fieldline15
           fi           
          
          #                       مشخص کردن اسب پیشتاز.
          HIGHEST_POS=`cat *position | sort -n | tail -1`          
          
          #                  تنظیم رنگ پس‌زمینه به سفید.
          echo -ne '\E[47m'
          tput cup 17 0
          echo -n Current leader: `grep -w $HIGHEST_POS *position | cut -c7`\
	  "                              "

done  

#           مشخص نمودن زمانی که مسابقه پایان یافته است.
FINISH_TIME=`date +%s`

#    تنظیم رنگ پس‌زمینه به سبز و فعال کردن چشمک زدن متن.
echo -ne '\E[30;42m'
echo -en '\E[5m'

#               چشمک زن ساختن اسبی که برنده گردیده است.
tput cup `expr $MOVE_HORSE + 5` \
`cat  horse_${MOVE_HORSE}_position | head -n 1`
$DRAW_HORSE

#                          غیر فعال نمودن چشمک زدن متن.
echo -en '\E[25m'

#                 تنظیم رنگ پیش‌زمینه و پس‌زمینه به سفید.
echo -ne '\E[37;47m'
move_and_echo 18 1 $BLANK80

#                           تنظیم رنگ پیش‌زمینه به سیاه.
echo -ne '\E[30m'

# ایجاد winner چشمک‌زن.
tput cup 17 0
echo -e "\E[5mWINNER: $MOVE_HORSE\E[25m""  Odds: `cat odds_${MOVE_HORSE}`"\
"  Race time: `expr $FINISH_TIME - $START_TIME` secs"

#                       بازیابی مکان‌نما و رنگ‌های قدیمی.
echo -en "\E[?25h"
echo -en "\E[0m"

#                                   بازیابی echo نمودن.
stty echo

#                       حذف کردن دایرکتوری موقت مسابقه.
rm -rf $HORSE_RACE_TMP_DIR

tput cup 19 0

exit 0

مترجم: اگر به دلیل عدم وجود usleep در سیستم، موقع اجرای اسکریپت، در خط مسابقه پیغام خطا ظاهر می‌گردد، می‌توانید usleep در سطر ‎usleep $USLEEP_ARG‎ را با sleep تعویض نمایید.

همچنین مثال ‎A-21‎، مثال ‎A-44‎، مثال ‎A-52‎، و مثال ‎A-40‎ را ببینید.


Caution

به هر حال، با تمام اینها یک مشکل اصلی وجود دارد. رشته‌های ‎ANSI escape‎ به طور قطعی غیر قابل حمل هستند. آنچه روی برخی شبیه‌سازهای ترمینال (یا کنسول) به خوبی کار می‌کند ممکن است در سایرین به طور متفاوتی عمل نماید یا اصلا کار نکند. یک اسکریپت «رنگی شده» که به نظر نویسنده آن جذاب است، می‌تواند برای شخص دیگری خروجی غیرقابل خواندنی تولید نماید. این تا اندازه‌ای سودمندی اسکریپت را به خطر می‌اندازد، و احتمالا این تکنیک را به جایگاه وسیله‌ای برای جلب‌توجه تنزل می‌دهد. اسکریپت‌های رنگی شده احتمالاً در یک زمینه تجاری نامناسب هستند، یعنی سرپرست شما می‌تواند تایید نکند.

برنامه سودمند ansi-color نوشته Alister (بر اساس Moshe Jacobson's color utility) به طور قابل ملاحظه‌ای استفاده از رشته‌های ‎ANSI escape‎ را ساده‌سازی می‌کند. این برنامه برای ساختارهای بد ترکیبی که الساعه مطرح گردید، یک گرامر پاکیزه و منطقی جایگزین می‌نماید.

به همچنین ‎Henry/teikedvl‎ یک برنامه سودمند (‎http://scriptechocolor.sourceforge.net/‎) برای ساده کردن ایجاد اسکریپت‌های رنگی تولید کرده است.

یادداشت‌ها

[1]

البته، ANSI یک سرنام برای ‎American National Standards Institute‎ (انجمن استانداردهای ملی امریکا) می‌باشد. این گروه ارجمند، استانداردهای متنوع صنعتی و تکنیکی را برقرار و پشتیبانی می‌نماید.