感受一下完美的Shell脚本编写规范


说到代码规范,其实每个程序员都很关注这一点,只是换成系统管理员来说就没那么重视咯。看起来舒服、注释到位的代码是衡量一段代码质量的标准之一,24个人是这么认为哈。但是SA每天的工作不是一直在写代码,也许更多的是敲命令。所以写脚本的时候,更为关注的应该是代码执行质量、运行效果而不是规范性。当然,这不是说大批的linux SA写脚本没有规范性,不好看。24还是见过不少牛逼人物写的代码看起来很顺眼的,注释到位,提示合理,顺序清晰。刚好今天打酱油看到一篇shell脚本,写的非常好,是一个游戏脚本--“挖地雷”。像代码注释段,该有的信息都有,显得非常专业化,再者脚本的内容也看起来很舒服,可以说是化难为易。当然了,这里不是推荐大伙们去研究这段脚本,而是体会一下他的书写规范。不过能够把下面的内容理解了,自己在此基础上改进发布改进版,那是再好不过的事情啦。这段代码测试没问题的,24已经验证过了:

  1. #!/bin/bash  
  2. #-------------CopyRight-------------  
  3. #   Name:Mine Sweeping  
  4. #   Version Number:1.00  
  5. #   Type:game  
  6. #   Language:bash shell  
  7. #   Date:2005-10-26  
  8. #   Author:BitBull  
  9. #   Email:BitBull.cn(at)gmail.com  
  10. #------------Environment------------  
  11. #   Terminal: column 80 line 24  
  12. #   Linux 2.6.9 i686  
  13. #   GNU Bash 3.00.15  
  14. #-----------------------------------  
  15.  
  16. #---------------Define--------------  
  17. ECHO="echo -ne" 
  18. ESC="\033[" 
  19.  
  20. OK=0 
  21. FALSE=1 
  22. #--------------Variable--------------  
  23. #ANSI ESC action  
  24. FLASH=5 
  25. REV=7 
  26.  
  27. #color  
  28. NULL=0 
  29. BLACK=30 
  30. RED=31 
  31. GREEN=32 
  32. ORANGE=33 
  33. BLUE=34 
  34. PURPLE=35 
  35. SBLUE=36 
  36. GREY=37 
  37.  
  38. #back color  
  39. BBLACK=40 
  40. BRED=41 
  41. BGREEN=42 
  42. BORANGE=43 
  43. BBLUE=44 
  44. BPURPLE=45 
  45. BSBLUE=46 
  46. BGREY=47 
  47.  
  48. MINE='@' 
  49. FLAG='F' 
  50. NUL=' ' 
  51. SHADOW='X' 
  52.  
  53. X=0 
  54. Y=0 
  55. CurX=1 #cur's X  
  56. CurY=1 #cur's Y  
  57. OCurX=1 #old cur's X  
  58. OCurY=1 #old cur's Y  
  59. MCount=0 #count mine  
  60. FCount=0 #count flag  
  61. SCount=0 #count shadow  
  62. MXYp=0 #MXY Array's ptr  
  63. #---------------Array----------------  
  64.  
  65. #if ${XY[]} == M { mine }  
  66. #if ${XY[]} == F { flag }  
  67. #if ${XY[]} == N { null }  
  68. #if ${XY[]} == S { shadow }  
  69. #if ${XY[]} == [1-8] { tip_num }  
  70. #${XY[]} init in XYInit(i)  
  71.  
  72. MXY[0]=""  
  73.  
  74. #--------------Function--------------  
  75.  
  76. function SttyInit ()  
  77. {  
  78.         stty_save=$(stty -g) #backup stty  
  79.  
  80.         clear  
  81.         trap "GameExit;" 2 15 
  82.         stty -echo  
  83.  
  84.         $ECHO "${ESC}?25l" #hidden cursor  
  85.           
  86.         return $OK  
  87. }  
  88.  
  89. function GameExit ()  
  90. {  
  91.         stty $stty_save  
  92.         stty echo  
  93.         clear  
  94.         trap 2 15 
  95.         $ECHO "${ESC}?25h${ESC}0;0H${ESC}0m" 
  96.  
  97.         exit $OK  
  98. }  
  99.  
  100. #print help  
  101. function Help ()  
  102. {  
  103.         msg="Move:w s a d Dig:j Flag:f NewGame:n Exit:x   --CopyRight-- -2005-10-28 BitBull--" 
  104.         $ECHO "${ESC}${REV};${RED}m${ESC}24;1H${msg}${ESC}${NULL}m" 
  105.  
  106.         return $OK  
  107. }  
  108.  
  109. #print dialog window in screen  
  110. function PMsg ()  
  111. {  
  112.         local title="$1" content="$2" greeting="$3" 
  113.  
  114.         $ECHO "${ESC}${RED}m" 
  115.         $ECHO "${ESC}11;20H ------------------------------------------- " 
  116.         $ECHO "${ESC}12;20H|         ======>$title<======           |" 
  117.         $ECHO "${ESC}13;20H|         $content          |" 
  118.         $ECHO "${ESC}14;20H|         ======>$greeting<======           |" 
  119.         $ECHO "${ESC}15;20H ------------------------------------------- " 
  120.         $ECHO "${ESC}${NULL}m" 
  121.  
  122.         return $OK  
  123. }  
  124.  
  125. #print menu and player choose level,then ${X,Y,MCount,FCount,SCount} init  
  126. function Menu ()  
  127. {  
  128.         local key  
  129.  
  130.         $ECHO "${ESC}6;1H${ESC}${RED}m" 
  131. cat<<MENUEND  
  132.                        +++++++++++++++++++++++++++++  
  133.                        +        (1) Easy           +  
  134.                        +        (2) Normal         +  
  135.                        +        (3) Hardly         +  
  136.                        +        (4) Exit           +  
  137.                        +++++++++++++++++++++++++++++  
  138. MENUEND  
  139.         $ECHO "${ESC}${NULL}m" 
  140.  
  141.         while read -s -n 1 key  
  142.         do  
  143.                 case $key in 
  144.                 1) X=10;Y=10;MCount=10;FCount=10;SCount=100;break 
  145.                 ;;  
  146.                 2) X=20;Y=14;MCount=28;FCount=28;SCount=280;break 
  147.                 ;;  
  148.                 3) X=36;Y=18;MCount=65;FCount=65;SCount=648;break 
  149.                 ;;  
  150.                 4) GameExit  
  151.                 ;;  
  152.                 esac  
  153.         done  
  154.  
  155.         return $OK  
  156. }          
  157.  
  158. #receive CurX CurY,put it into XY[CurX+X*(CurY-1))]  
  159. #if $# == 3;write into XY[]  
  160. #if $# == 2;read from XY[]  
  161. function XYFormat ()  
  162. {  
  163.         local XTmp=$1 YTmp=$2 
  164.  
  165.         if [[ $# -eq 3 ]]  
  166.         then XY[$XTmp+$X*($YTmp-1)]=$3 
  167.         else echo ${XY[$XTmp+$X*($YTmp-1)]}  
  168.         fi          
  169.           
  170.         return $OK  
  171. }  
  172.  
  173. function DrawInit ()  
  174. {  
  175.         local DIline DIline2  
  176.  
  177.         DIline=$( for (( i=1; i<$((X*2)); i++ )) do $ECHO '-';done )  
  178.         DIline2=$( for (( i=0; i<X; i++ )) do $ECHO "|${ESC}${SBLUE}mX${ESC}${NULL}m";done )  
  179.  
  180.         clear  
  181.         Help  
  182.           
  183.         $ECHO "${ESC}1;1H+${DIline}+" 
  184.         for (( i=0; i<Y; i++ ))  
  185.         do  
  186.                 $ECHO "${ESC}$((i+2));1H${DIline2}|" 
  187.         done  
  188.         $ECHO "${ESC}$((Y+2));1H+${DIline}+" 
  189.  
  190.         return $OK  
  191. }  
  192.  
  193. #${XY[*]}=S  
  194. function XYInit ()  
  195. {  
  196.         for (( i=1; i<=$X; i++ ))  
  197.         do  
  198.                 for (( j=1; j<=$Y; j++ ))  
  199.                 do  
  200.                         XYFormat $i $j S  
  201.                 done  
  202.         done  
  203.         return $OK  
  204. }  
  205.  
  206. #check X Y  
  207. function CheckXY ()  
  208. {  
  209.         local XYTmp="$1 $2" 
  210.  
  211.         for(( i=0; i<MXYp; i++ ))  
  212.         do  
  213.                 if [[ "${MXY[i]}" == "$XYTmp" ]]  
  214.                 then return $FALSE  
  215.                 fi  
  216.         done  
  217.  
  218.         return $OK  
  219. }  
  220.  
  221. #RANDOM mine's X Y  
  222. function XYRand ()  
  223. {  
  224.         local XTmp YTmp  
  225.  
  226.         for(( i=0; i<MCount; i++ ))  
  227.         do  
  228.                 while :   
  229.                 do  
  230.                         XTmp=$(( RANDOM % ( X - 1 ) + 1 ))  
  231.                         YTmp=$(( RANDOM % ( Y - 1 ) + 1 ))  
  232.                         CheckXY $XTmp $YTmp  
  233.  
  234.                         if [[ "$?" == "$OK" ]]  
  235.                         then  
  236.                                 XYFormat $XTmp $YTmp M  
  237.                                 MXY[i]="$XTmp $YTmp" 
  238.                                 (( ++MXYp ))  
  239.                                 break 
  240.                         else continue 
  241.                         fi  
  242.                 done  
  243.         done  
  244.           
  245.         return $OK  
  246. }  
  247.  
  248. #DEBUG  
  249. # print ${XY[*]} into ./mine.tmp  
  250. #you can read mine.tmp to know where is mine,xixi~~:)  
  251. #M is mine  
  252. function DEBUGPXY ()  
  253. {  
  254.         rm mine.tmp>/dev/null 2>&1 
  255.         for(( i=1; i<=$Y; i++ ))  
  256.         do  
  257.                 for(( j=1; j<=$X; j++))  
  258.                 do  
  259.                         $ECHO "$(XYFormat $j $i)">>mine.tmp  
  260.                 done  
  261.                 $ECHO "\n">>mine.tmp  
  262.         done  
  263.  
  264.         return $OK  
  265. }  
  266.  
  267. #move cur  
  268. #usage:CurMov [UP|DOWN|LEFT|RIGHT]  
  269. function CurMov ()  
  270. {  
  271.         local direction=$1 Xmin=1 Ymin=1 Xmax=$X Ymax=$Y  
  272.  
  273.         OCurX=$CurX  
  274.         OCurY=$CurY  
  275.  
  276.         case $direction        in 
  277.         "UP")        if [[ $CurY -gt $Ymin ]];then (( CurY-- ));fi  
  278.         ;;  
  279.         "DOWN")        if [[ $CurY -lt $Ymax ]];then (( CurY++ ));fi  
  280.         ;;  
  281.         "LEFT"if [[ $CurX -gt $Xmin ]];then (( CurX-- ));fi  
  282.         ;;  
  283.         "RIGHT")if [[ $CurX -lt $Xmax ]];then (( CurX++ ));fi  
  284.         ;;  
  285.         esac  
  286.  
  287.         if [[ $CurX != $OCurX || $CurY != $OCurY ]]  
  288.         then DrawPoint $CurX $CurY CUR  
  289.         fi  
  290.  
  291.         return $OK  
  292. }  
  293.  
  294. #display point  
  295. #include cur,flag,mine,shadow,nul,tip [1-8]  
  296. function DrawPoint ()  
  297. {  
  298.         local TCurX=$(( $1 * 2 )) TCurY=$(( $2 + 1 )) Type=$3 
  299.         local TOCurX=$(( OCurX * 2 )) TOCurY=$(( OCurY + 1 ))  
  300.         local colr=0 osign=0 sign=0 
  301.           
  302.         case $Type in 
  303.         "CUR")  
  304.                 case $(XYFormat $OCurX $OCurY) in 
  305.                 F)        colr=$PURPLE;osign=$FLAG;;  
  306.                 N)        colr=$NULL;osign=$NUL;;  
  307.                 [1-8])        colr=$ORANGE;osign=$(XYFormat $OCurX $OCurY);;  
  308.                 [SM])        colr=$SBLUE;osign=$SHADOW;;  
  309.                 esac  
  310.  
  311.                 case $(XYFormat $CurX $CurY) in 
  312.                 F)      sign=$FLAG;;  
  313.                 N)      sign=$NUL;;  
  314.                 [1-8])        sign=$(XYFormat $CurX $CurY);;  
  315.                 [SM])     sign=$SHADOW;;  
  316.                 esac  
  317.  
  318.                 $ECHO "${ESC}${colr}m${ESC}${TOCurY};${TOCurX}H${osign}${ESC}${NULL}m" 
  319.                 $ECHO "${ESC}${REV};${FLASH};${ORANGE}m${ESC}${TCurY};${TCurX}H${sign}${ESC}${NULL}m" 
  320.         ;;  
  321.         "SHADOW")  
  322.                 $ECHO "${ESC}${SBLUE}m${ESC}${TCurY};${TCurX}H${SHADOW}${ESC}${NULL}m" 
  323.         ;;  
  324.         "MINE")   
  325.                 $ECHO "${ESC}${REV};${RED}m${ESC}${TCurY};${TCurX}H${MINE}${ESC}${NULL}m" 
  326.         ;;  
  327.         "FLAG")  
  328.                 $ECHO "${ESC}${TCurY};${TCurX}H${ESC}${PURPLE}m${FLAG}${ESC}${NULL}m" 
  329.         ;;  
  330.         [1-8])  
  331.                 $ECHO "${ESC}${TCurY};${TCurX}H${ESC}${ORANGE}m${Type}${ESC}${NULL}m" 
  332.         ;;  
  333.         "NUL")  
  334.                 $ECHO "${ESC}${TCurY};${TCurX}H${NUL}" 
  335.         esac          
  336.  
  337.         return $OK  
  338. }  
  339.  
  340. #check xy  
  341. function Loop ()  
  342. {  
  343.         local XYTmp="$1 $2" 
  344.  
  345.         for (( i=0; i<MXYp; i++ ))  
  346.         do  
  347.                 if [[ "$XYTmp" == "${MXY[i]}" ]]  
  348.                 then $ECHO 1 
  349.                 fi  
  350.         done  
  351.  
  352.         return $OK  
  353. }  
  354.  
  355. #count around mine  
  356. #A B C  
  357. #D X E  
  358. #F G H  
  359. #return mine's number  
  360. function CountM ()  
  361. {  
  362.         local Xmin=1 Ymin=1 Xmax=$X Ymax=$Y minecount=0 n=0 
  363. #A  
  364.         if [[ ( $CurX -gt $Xmin ) && ( $CurY -gt $Ymin ) ]]  
  365.         then  
  366.                 n=$( Loop $((CurX-1)) $((CurY-1)) )  
  367.                 (( minecount += n ))  
  368.                 n=0 
  369.         fi  
  370. #B  
  371.         if [[ $CurY -gt $Ymin ]]  
  372.         then  
  373.                 n=$( Loop $CurX $((CurY-1)) )  
  374.                 (( minecount += n ))  
  375.                 n=0 
  376.         fi  
  377. #C  
  378.         if [[ ( $CurX -lt $Xmax ) && ( $CurY -gt $Ymin ) ]]  
  379.         then  
  380.                 n=$( Loop $((CurX+1)) $((CurY-1)) )  
  381.                 (( minecount += n ))  
  382.                 n=0 
  383.         fi  
  384. #D  
  385.         if [[ $CurX -gt $Xmin ]]  
  386.         then  
  387.                 n=$( Loop $((CurX-1)) $CurY )  
  388.                 (( minecount += n ))  
  389.                 n=0 
  390.         fi  
  391. #E  
  392.         if [[ $CurX -lt $Xmax ]]  
  393.         then  
  394.                 n=$( Loop $((CurX+1)) $CurY )  
  395.                 (( minecount += n ))  
  396.                 n=0 
  397.         fi  
  398. #F  
  399.         if [[ ( $CurX -gt $Xmin ) && ( $CurY -lt $Ymax ) ]]  
  400.         then  
  401.                 n=$( Loop $((CurX-1)) $((CurY+1)) )  
  402.                 (( minecount += n ))  
  403.                 n=0 
  404.         fi  
  405. #G  
  406.         if [[ $CurY -lt $Ymax ]]  
  407.         then   
  408.                 n=$( Loop $CurX $((CurY+1)) )  
  409.                 (( minecount += n ))  
  410.                 n=0 
  411.         fi  
  412. #H  
  413.         if [[ ( $CurX -lt $Xmax ) && ( $CurY -lt $Ymax ) ]]  
  414.         then  
  415.                 n=$( Loop $((CurX+1)) $((CurY+1)) )  
  416.                 (( minecount += n ))  
  417.                 n=0 
  418.         fi  
  419.  
  420.         return $minecount  
  421. }  
  422.  
  423. #dig  
  424. #if mine ,gameover  
  425. #else tip around mine's number  
  426. function Dig ()  
  427. {  
  428.         local key minenum=0 
  429.  
  430.         case $(XYFormat $CurX $CurY) in 
  431.         M)  
  432.                 DrawPoint $CurX $CurY MINE  
  433.                 read -s -n 1 key  
  434.                 GameOver "Game Over" 
  435.         ;;  
  436.         S)  
  437.                 CountM  
  438.                 minenum=$?  
  439.                 if [[ $minenum -eq $NULL ]]  
  440.                 then  
  441.                         XYFormat $CurX $CurY N  
  442.                         DrawPoint $CurX $CurY NUL  
  443.                 else 
  444.                         XYFormat $CurX $CurY $minenum  
  445.                         DrawPoint $CurX $CurY $minenum  
  446.                 fi  
  447.           
  448.                 (( SCount-- ))  
  449.                 if [[ $SCount -eq $MCount ]]  
  450.                 then GameOver "Well Done" 
  451.                 fi          
  452.         ;;  
  453.         esac  
  454.         DrawPoint $CurX $CurY CUR  
  455.  
  456.         return $OK  
  457. }  
  458.  
  459. #draw flag's number  
  460. function DrawFCount ()  
  461. {  
  462.         $ECHO "${ESC}22;34H${ESC};${PURPLE}mFLAG=${FCount}  ${ESC}${NULL}m" 
  463. }  
  464.  
  465. #sign mine  
  466. function Flag ()  
  467. {  
  468.         local XYTmp="$CurX $CurY";stat=$FALSE  
  469.  
  470.         case $(XYFormat $CurX $CurY) in 
  471.         F)  
  472.                 for (( i=1; i<MXYp; i++ ))  
  473.                 do  
  474.                         if [[ "${MXY[i]}" == "$XYTmp" ]]  
  475.                         then XYFormat $CurX $CurY M;stat=$OK;break 
  476.                         fi  
  477.                 done  
  478.                 if [[ $stat == $FALSE ]]  
  479.                 then XYFormat $CurX $CurY S  
  480.                 fi  
  481.  
  482.                 DrawPoint $CurX $CurY SHADOW  
  483.                 (( FCount++ ))  
  484.                 DrawFCount  
  485.         ;;  
  486.         [SM])          
  487.                 if [[ $FCount -eq $NULL ]]  
  488.                 then return $FALSE  
  489.                 fi  
  490.  
  491.                 DrawPoint $CurX $CurY FLAG  
  492.                 XYFormat $CurX $CurY F  
  493.                 (( FCount-- ))  
  494.                 DrawFCount  
  495.         ;;  
  496.         esac  
  497.         DrawPoint $CurX $CurY CUR  
  498.  
  499.         return $OK  
  500. }  
  501.  
  502. function GameOver ()  
  503. {  
  504.         local key msgtitle=$1 
  505.  
  506.         PMsg "$msgtitle" "Do you want replay?<y/n>" "Thank You" 
  507.         while read -s -n 1 key  
  508.         do  
  509.                 case $key in 
  510.                 [yY])        exec $(dirname $0)/$(basename $0);;  
  511.                 [nN])        GameExit;;  
  512.                 *)        continue;;  
  513.                 esac  
  514.         done  
  515.  
  516.         return $OK          
  517. }  
  518.           
  519. #main  
  520. #drawscreen and control  
  521. function Main ()  
  522. {  
  523.         local key  
  524.  
  525.         XYInit  
  526.         XYRand  
  527. ############################  
  528. # if you enable DEBUGPXY,  
  529. #you can know where is mine  
  530. #        DEBUGPXY  #delete this line's #  
  531. #then cat ./mine.tmp  
  532. ############################          
  533.  
  534.         DrawPoint $CurX $CurY CUR  
  535.         DrawFCount          
  536.  
  537.         while read -s -n 1 key  
  538.         do  
  539.                 case $key in 
  540.                 [wW])        CurMov UP;;  
  541.                 [sS])        CurMov DOWN;;  
  542.                 [aA])        CurMov LEFT;;  
  543.                 [dD])        CurMov RIGHT;;  
  544.                 [jJ])        Dig;;  
  545.                 [fF])        Flag;;  
  546.                 [nN])        exec $(dirname $0)/$(basename $0);;  
  547.                 [xX])        GameExit;;  
  548.                 esac  
  549.         done  
  550.  
  551.         return $OK  
  552. }  
  553. #---------------Main-----------------  
  554.  
  555. SttyInit  
  556. Menu #X Y MCount FCount SCount OK!  
  557. DrawInit  
  558. Main  

相关内容