bashver2.html
来自「BASH Shell 编程 经典教程 《高级SHELL脚本编程》中文版」· HTML 代码 · 共 580 行
HTML
580 行
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><HTML><HEAD><TITLE>Bash, 版本2</TITLE><METANAME="GENERATOR"CONTENT="Modular DocBook HTML Stylesheet Version 1.79"><LINKREL="HOME"TITLE="高级Bash脚本编程指南"HREF="index.html"><LINKREL="UP"TITLE="Bash, 版本2与版本3"HREF="bash2.html"><LINKREL="PREVIOUS"TITLE="Bash, 版本2与版本3"HREF="bash2.html"><LINKREL="NEXT"TITLE="Bash, 版本3"HREF="bashver3.html"></HEAD><BODYCLASS="SECT1"BGCOLOR="#FFFFFF"TEXT="#000000"LINK="#0000FF"VLINK="#840084"ALINK="#0000FF"><DIVCLASS="NAVHEADER"><TABLESUMMARY="Header navigation table"WIDTH="100%"BORDER="0"CELLPADDING="0"CELLSPACING="0"><TR><THCOLSPAN="3"ALIGN="center">高级Bash脚本编程指南: 一本深入学习shell脚本艺术的书籍</TH></TR><TR><TDWIDTH="10%"ALIGN="left"VALIGN="bottom"><AHREF="bash2.html"ACCESSKEY="P">前一页</A></TD><TDWIDTH="80%"ALIGN="center"VALIGN="bottom">34. Bash, 版本2与版本3</TD><TDWIDTH="10%"ALIGN="right"VALIGN="bottom"><AHREF="bashver3.html"ACCESSKEY="N">下一页</A></TD></TR></TABLE><HRALIGN="LEFT"WIDTH="100%"></DIV><DIVCLASS="SECT1"><H1CLASS="SECT1"><ANAME="BASHVER2">34.1. Bash, 版本2</A></H1><P><ANAME="BASH2REF"></A></P><P>当前比较流行的<EM>Bash</EM>版本有两个, 版本2.xx.y或版本3.xx.y, 这两个中的某一个估计就运行在你的机器上. <TABLEBORDER="1"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="SCREEN"><SAMPCLASS="PROMPT">bash$ </SAMP><KBDCLASS="USERINPUT">echo $BASH_VERSION</KBD><SAMPCLASS="COMPUTEROUTPUT">2.05.b.0(1)-release</SAMP> </PRE></FONT></TD></TR></TABLE> 经典Bash脚本语言版本2的主要升级内容, 增加了数组变量, <ANAME="AEN16155"HREF="#FTN.AEN16155"><SPANCLASS="footnote">[1]</SPAN></A> 字符串和参数扩展, 还添加了间接变量引用的一种更好的方法, 以及其他特性. </P><DIVCLASS="EXAMPLE"><HR><ANAME="EX77"></A><P><B>例子 34-1. 字符串扩展</B></P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="PROGRAMLISTING"> 1 #!/bin/bash 2 3 # 字符串扩展. 4 # Bash版本2中引入的特性. 5 6 # $'xxx'格式的字符串 7 #+ 具备解释里面标准转义字符的能力. 8 9 echo $'Ringing bell 3 times \a \a \a' 10 # 可能在某些终端中, 只会响一次铃. 11 echo $'Three form feeds \f \f \f' 12 echo $'10 newlines \n\n\n\n\n\n\n\n\n\n' 13 echo $'\102\141\163\150' # Bash 14 # 8进制的等价字符. 15 16 exit 0</PRE></FONT></TD></TR></TABLE><HR></DIV><P><ANAME="VARREFNEW"></A></P><DIVCLASS="EXAMPLE"><HR><ANAME="EX78"></A><P><B>例子 34-2. 间接变量引用 - 新方法</B></P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="PROGRAMLISTING"> 1 #!/bin/bash 2 3 # 间接变量引用. 4 # 这种方法比较像C++中的引用特性. 5 6 7 a=letter_of_alphabet 8 letter_of_alphabet=z 9 10 echo "a = $a" # 直接引用. 11 12 echo "Now a = ${!a}" # 间接引用. 13 # ${!variable}表示法比老式的"eval var1=\$$var2"表示法高级的多. 14 15 echo 16 17 t=table_cell_3 18 table_cell_3=24 19 echo "t = ${!t}" # t = 24 20 table_cell_3=387 21 echo "Value of t changed to ${!t}" # 387 22 23 # 在引用数组成员或者引用表的时候, 这种方法非常有用, 24 #+ 还可以用来模拟多维数组. 25 # 如果有能够索引的选项(类似于指针的算术运算) 26 #+ 就更好了. 可惜. 27 28 exit 0</PRE></FONT></TD></TR></TABLE><HR></DIV><DIVCLASS="EXAMPLE"><HR><ANAME="RESISTOR"></A><P><B>例子 34-3. 使用间接变量引用的简单数据库应用</B></P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="PROGRAMLISTING"> 1 #!/bin/bash 2 # resistor-inventory.sh 3 # 使用间接变量引用的简单数据库应用. 4 5 # ============================================================== # 6 # 数据 7 8 B1723_value=470 # 欧姆 9 B1723_powerdissip=.25 # 瓦特 10 B1723_colorcode="yellow-violet-brown" # 颜色 11 B1723_loc=173 # 位置 12 B1723_inventory=78 # 数量 13 14 B1724_value=1000 15 B1724_powerdissip=.25 16 B1724_colorcode="brown-black-red" 17 B1724_loc=24N 18 B1724_inventory=243 19 20 B1725_value=10000 21 B1725_powerdissip=.25 22 B1725_colorcode="brown-black-orange" 23 B1725_loc=24N 24 B1725_inventory=89 25 26 # ============================================================== # 27 28 29 echo 30 31 PS3='Enter catalog number: ' 32 33 echo 34 35 select catalog_number in "B1723" "B1724" "B1725" 36 do 37 Inv=${catalog_number}_inventory 38 Val=${catalog_number}_value 39 Pdissip=${catalog_number}_powerdissip 40 Loc=${catalog_number}_loc 41 Ccode=${catalog_number}_colorcode 42 43 echo 44 echo "Catalog number $catalog_number:" 45 echo "There are ${!Inv} of [${!Val} ohm / ${!Pdissip} watt] resistors in stock." 46 echo "These are located in bin # ${!Loc}." 47 echo "Their color code is \"${!Ccode}\"." 48 49 break 50 done 51 52 echo; echo 53 54 # 练习: 55 # ----- 56 # 1) 重写脚本, 使其从外部文件读取数据. 57 # 2) 重写脚本, 58 #+ 用数组来代替间接变量引用, 59 # 因为使用数组更简单, 更易懂. 60 61 62 # 注: 63 # --- 64 # 除了最简单的数据库应用, 事实上, Shell脚本本身并不适合于数据库应用. 65 #+ 因为它太依赖于工作环境和机器的运算能力. 66 # 更好的办法还是使用支持数据结构的本地语言, 67 #+ 比如C++或者Java(或者甚至可以是Perl). 68 69 exit 0</PRE></FONT></TD></TR></TABLE><HR></DIV><DIVCLASS="EXAMPLE"><HR><ANAME="EX79"></A><P><B>例子 34-4. 使用数组和其他的小技巧来处理4人随机打牌</B></P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="PROGRAMLISTING"> 1 #!/bin/bash 2 3 # 纸牌: 4 # 处理4人打牌. 5 6 UNPICKED=0 7 PICKED=1 8 9 DUPE_CARD=99 10 11 LOWER_LIMIT=0 12 UPPER_LIMIT=51 13 CARDS_IN_SUIT=13 14 CARDS=52 15 16 declare -a Deck 17 declare -a Suits 18 declare -a Cards 19 # 使用一个3维数组来代替这3个一维数组来描述数据, 20 #+ 可以更容易实现, 而且可以增加可读性. 21 # 或许在Bash未来的版本上会支持多维数组. 22 23 24 initialize_Deck () 25 { 26 i=$LOWER_LIMIT 27 until [ "$i" -gt $UPPER_LIMIT ] 28 do 29 Deck[i]=$UNPICKED # 将整副"牌"的每一张都设置为无人持牌的状态. 30 let "i += 1" 31 done 32 echo 33 } 34 35 initialize_Suits () 36 { 37 Suits[0]=C #梅花 38 Suits[1]=D #方块 39 Suits[2]=H #红心 40 Suits[3]=S #黑桃 41 } 42 43 initialize_Cards () 44 { 45 Cards=(2 3 4 5 6 7 8 9 10 J Q K A) 46 # 另一种初始化数组的方法. 47 } 48 49 pick_a_card () 50 { 51 card_number=$RANDOM 52 let "card_number %= $CARDS" 53 if [ "${Deck[card_number]}" -eq $UNPICKED ] 54 then 55 Deck[card_number]=$PICKED 56 return $card_number 57 else 58 return $DUPE_CARD 59 fi 60 } 61 62 parse_card () 63 { 64 number=$1 65 let "suit_number = number / CARDS_IN_SUIT" 66 suit=${Suits[suit_number]} 67 echo -n "$suit-" 68 let "card_no = number % CARDS_IN_SUIT" 69 Card=${Cards[card_no]} 70 printf %-4s $Card 71 # 使用整洁的列形式来打印每张牌. 72 } 73 74 seed_random () # 种子随机数产生器. 75 { # 如果不这么做, 会发生什么? 76 seed=`eval date +%s` 77 let "seed %= 32766" 78 RANDOM=$seed 79 # 还有其他的方法 80 #+ 能够产生种子随机数么? 81 } 82 83 deal_cards () 84 { 85 echo 86 87 cards_picked=0 88 while [ "$cards_picked" -le $UPPER_LIMIT ] 89 do 90 pick_a_card 91 t=$? 92 93 if [ "$t" -ne $DUPE_CARD ] 94 then 95 parse_card $t 96 97 u=$cards_picked+1 98 # 将数组索引改为从1(译者注: 数组都是从0开始索引的)开始(临时的). 为什么? 99 let "u %= $CARDS_IN_SUIT"100 if [ "$u" -eq 0 ] # 内嵌的if/then条件测试. 101 then102 echo103 echo104 fi105 # 分手. 106 107 let "cards_picked += 1"108 fi 109 done 110 111 echo112 113 return 0114 }115 116 117 # 结构化编程: 118 # 将函数中的整个程序逻辑模块化. 119 120 #================121 seed_random122 initialize_Deck123 initialize_Suits124 initialize_Cards125 deal_cards126 #================127 128 exit 0129 130 131 132 # 练习1:133 # 完整的注释这个脚本. 134 135 # 练习2:136 # 添加一个例程(函数)按照花色打印出每手牌. 137 # 如果你喜欢, 可以添加任何你想要添加的代码. 138 139 # 练习3:140 # 简化并理顺脚本逻辑. </PRE></FONT></TD></TR></TABLE><HR></DIV></DIV><H3CLASS="FOOTNOTES">注意事项</H3><TABLEBORDER="0"CLASS="FOOTNOTES"WIDTH="100%"><TR><TDALIGN="LEFT"VALIGN="TOP"WIDTH="5%"><ANAME="FTN.AEN16155"HREF="bashver2.html#AEN16155"><SPANCLASS="footnote">[1]</SPAN></A></TD><TDALIGN="LEFT"VALIGN="TOP"WIDTH="95%"><P>Chet Ramey承诺会在Bash未来的版本中支持关联数组(一个Perl特性). 但是到了版本3, 他的承诺还没兑现. </P></TD></TR></TABLE><DIVCLASS="NAVFOOTER"><HRALIGN="LEFT"WIDTH="100%"><TABLESUMMARY="Footer navigation table"WIDTH="100%"BORDER="0"CELLPADDING="0"CELLSPACING="0"><TR><TDWIDTH="33%"ALIGN="left"VALIGN="top"><AHREF="bash2.html"ACCESSKEY="P">前一页</A></TD><TDWIDTH="34%"ALIGN="center"VALIGN="top"><AHREF="index.html"ACCESSKEY="H">首页</A></TD><TDWIDTH="33%"ALIGN="right"VALIGN="top"><AHREF="bashver3.html"ACCESSKEY="N">下一页</A></TD></TR><TR><TDWIDTH="33%"ALIGN="left"VALIGN="top">Bash, 版本2与版本3</TD><TDWIDTH="34%"ALIGN="center"VALIGN="top"><AHREF="bash2.html"ACCESSKEY="U">上一级</A></TD><TDWIDTH="33%"ALIGN="right"VALIGN="top">Bash, 版本3</TD></TR></TABLE></DIV></BODY></HTML>
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?