⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 arrays.html

📁 BASH Shell 编程 经典教程 《高级SHELL脚本编程》中文版
💻 HTML
📖 第 1 页 / 共 5 页
字号:
 22&nbsp;if [ -z "$1" ]    # 没有可压入的数据项?  23&nbsp;then 24&nbsp;  return 25&nbsp;fi 26&nbsp; 27&nbsp;let "SP -= 1"     # 更新栈指针.  28&nbsp;stack[$SP]=$1 29&nbsp; 30&nbsp;return 31&nbsp;} 32&nbsp; 33&nbsp;pop()                    # 从栈中弹出数据项.  34&nbsp;{ 35&nbsp;Data=                    # 清空保存数据项的中间变量.  36&nbsp; 37&nbsp;if [ "$SP" -eq "$BP" ]   # 栈空?  38&nbsp;then 39&nbsp;  return 40&nbsp;fi                       #  这使得SP不会超过100,  41&nbsp;                         #+ 例如, 这可以防止堆栈失控.  42&nbsp; 43&nbsp;Data=${stack[$SP]} 44&nbsp;let "SP += 1"            # 更新栈指针.  45&nbsp;return 46&nbsp;} 47&nbsp; 48&nbsp;status_report()          # 打印当前状态.  49&nbsp;{ 50&nbsp;echo "-------------------------------------" 51&nbsp;echo "REPORT" 52&nbsp;echo "Stack Pointer = $SP" 53&nbsp;echo "Just popped \""$Data"\" off the stack." 54&nbsp;echo "-------------------------------------" 55&nbsp;echo 56&nbsp;} 57&nbsp; 58&nbsp; 59&nbsp;# ======================================================= 60&nbsp;# 现在, 来点乐子.  61&nbsp; 62&nbsp;echo 63&nbsp; 64&nbsp;# 看你是否能从空栈里弹出数据项来.  65&nbsp;pop 66&nbsp;status_report 67&nbsp; 68&nbsp;echo 69&nbsp; 70&nbsp;push garbage 71&nbsp;pop 72&nbsp;status_report     # 压入garbage, 弹出garbage.        73&nbsp; 74&nbsp;value1=23; push $value1 75&nbsp;value2=skidoo; push $value2 76&nbsp;value3=FINAL; push $value3 77&nbsp; 78&nbsp;pop              # FINAL 79&nbsp;status_report 80&nbsp;pop              # skidoo 81&nbsp;status_report 82&nbsp;pop              # 23 83&nbsp;status_report    # 后进, 先出!  84&nbsp; 85&nbsp;#  注意: 栈指针在压栈时减,  86&nbsp;#+ 在弹出时加.  87&nbsp; 88&nbsp;echo 89&nbsp; 90&nbsp;exit 0 91&nbsp; 92&nbsp;# ======================================================= 93&nbsp; 94&nbsp; 95&nbsp;# 练习: 96&nbsp;# ----- 97&nbsp; 98&nbsp;# 1)  修改"push()"函数,  99&nbsp;#   + 使其调用一次就能够压入多个数据项. 100&nbsp;101&nbsp;# 2)  修改"pop()"函数, 102&nbsp;#   + 使其调用一次就能弹出多个数据项. 103&nbsp;104&nbsp;# 3)  给那些有临界操作的函数添加出错检查. 105&nbsp;#     说明白一些, 就是让这些函数返回错误码, 106&nbsp;#   + 返回的错误码依赖于操作是否成功完成, 107&nbsp;#   + 如果没有成功完成, 那么就需要启动合适的处理动作. 108&nbsp;109&nbsp;# 4)  以这个脚本为基础, 110&nbsp;#   + 编写一个用栈实现的四则运算计算器. </PRE></FONT></TD></TR></TABLE><HR></DIV><P>--</P><P>如果想对数组<SPANCLASS="QUOTE">"下标"</SPAN>做一些比较诡异的操作, 		  可能需要使用中间变量. 		  对于那些有这种需求的项目来说, 还是应该考虑使用功能更加强大的编程语言, 		  比如Perl或C. </P><DIVCLASS="EXAMPLE"><HR><ANAME="QFUNCTION"></A><P><B>例子 26-15. 复杂的数组应用:              <EM>探索一个神秘的数学序列</EM></B></P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="PROGRAMLISTING">  1&nbsp;#!/bin/bash  2&nbsp;  3&nbsp;# Douglas Hofstadter的声名狼藉的序列"Q-series":  4&nbsp;  5&nbsp;# Q(1) = Q(2) = 1  6&nbsp;# Q(n) = Q(n - Q(n-1)) + Q(n - Q(n-2)), 当n&#62;2时  7&nbsp;  8&nbsp;# 这是一个令人感到陌生的, 没有规律的"乱序"整数序列.   9&nbsp;# 序列的头20项, 如下所示:  10&nbsp;# 1 1 2 3 3 4 5 5 6 6 6 8 8 8 10 9 10 11 11 12  11&nbsp; 12&nbsp;#  请参考相关书籍, Hofstadter的, "_Goedel, Escher, Bach: An Eternal Golden Braid_", 13&nbsp;#+ 第137页.  14&nbsp; 15&nbsp; 16&nbsp;LIMIT=100     # 需要计算的数列长度.  17&nbsp;LINEWIDTH=20  # 每行打印的个数.  18&nbsp; 19&nbsp;Q[1]=1        # 数列的头两项都为1.  20&nbsp;Q[2]=1 21&nbsp; 22&nbsp;echo 23&nbsp;echo "Q-series [$LIMIT terms]:" 24&nbsp;echo -n "${Q[1]} "             # 输出数列头两项.  25&nbsp;echo -n "${Q[2]} " 26&nbsp; 27&nbsp;for ((n=3; n &#60;= $LIMIT; n++))  # C风格的循环条件.  28&nbsp;do   # Q[n] = Q[n - Q[n-1]] + Q[n - Q[n-2]]  当n&#62;2时 29&nbsp;#  需要将表达式拆开, 分步计算,  30&nbsp;#+ 因为Bash不能够很好的处理复杂数组的算术运算.  31&nbsp; 32&nbsp;  let "n1 = $n - 1"        # n-1 33&nbsp;  let "n2 = $n - 2"        # n-2 34&nbsp;   35&nbsp;  t0=`expr $n - ${Q[n1]}`  # n - Q[n-1] 36&nbsp;  t1=`expr $n - ${Q[n2]}`  # n - Q[n-2] 37&nbsp;   38&nbsp;  T0=${Q[t0]}              # Q[n - Q[n-1]] 39&nbsp;  T1=${Q[t1]}              # Q[n - Q[n-2]] 40&nbsp; 41&nbsp;Q[n]=`expr $T0 + $T1`      # Q[n - Q[n-1]] + Q[n - Q[n-2]] 42&nbsp;echo -n "${Q[n]} " 43&nbsp; 44&nbsp;if [ `expr $n % $LINEWIDTH` -eq 0 ]    # 格式化输出.  45&nbsp;then   #      ^ 取模操作 46&nbsp;  echo # 把每行都拆为20个数字的小块.  47&nbsp;fi 48&nbsp; 49&nbsp;done 50&nbsp; 51&nbsp;echo 52&nbsp; 53&nbsp;exit 0 54&nbsp; 55&nbsp;# 这是Q-series的一个迭代实现.  56&nbsp;# 更直接明了的实现是使用递归, 请读者作为练习完成.  57&nbsp;# 警告: 使用递归的方法来计算这个数列的话, 会花费非常长的时间. </PRE></FONT></TD></TR></TABLE><HR></DIV><P>--</P><P>Bash仅仅支持一维数组, 但是我们可以使用一个小手段,         这样就可以模拟多维数组了. </P><DIVCLASS="EXAMPLE"><HR><ANAME="TWODIM"></A><P><B>例子 26-16. 模拟一个二维数组, 并使他倾斜</B></P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="PROGRAMLISTING">  1&nbsp;#!/bin/bash  2&nbsp;# twodim.sh: 模拟一个二维数组.   3&nbsp;  4&nbsp;# 一维数组由单行组成.   5&nbsp;# 二维数组由连续的多行组成.   6&nbsp;  7&nbsp;Rows=5  8&nbsp;Columns=5  9&nbsp;# 5 X 5 的数组. 10&nbsp; 11&nbsp;declare -a alpha     # char alpha [Rows] [Columns]; 12&nbsp;                     # 没必要声明. 为什么? 13&nbsp; 14&nbsp;load_alpha () 15&nbsp;{ 16&nbsp;local rc=0 17&nbsp;local index 18&nbsp; 19&nbsp;for i in A B C D E F G H I J K L M N O P Q R S T U V W X Y 20&nbsp;do     # 你可以随你的心意, 使用任意符号.  21&nbsp;  local row=`expr $rc / $Columns` 22&nbsp;  local column=`expr $rc % $Rows` 23&nbsp;  let "index = $row * $Rows + $column" 24&nbsp;  alpha[$index]=$i 25&nbsp;# alpha[$row][$column] 26&nbsp;  let "rc += 1" 27&nbsp;done   28&nbsp; 29&nbsp;#  更简单的方法:  30&nbsp;#+   declare -a alpha=( A B C D E F G H I J K L M N O P Q R S T U V W X Y ) 31&nbsp;#+ 但是如果写的话, 就缺乏二维数组的"风味"了.  32&nbsp;} 33&nbsp; 34&nbsp;print_alpha () 35&nbsp;{ 36&nbsp;local row=0 37&nbsp;local index 38&nbsp; 39&nbsp;echo 40&nbsp; 41&nbsp;while [ "$row" -lt "$Rows" ]   #  以"行序为主"进行打印:  42&nbsp;do                             #+ 行号不变(外层循环), 43&nbsp;                               #+ 列号进行增长. (译者注: 就是按行打印) 44&nbsp;  local column=0 45&nbsp; 46&nbsp;  echo -n "       "            #  按照行方向打印"正方形"数组.  47&nbsp; 48&nbsp;  while [ "$column" -lt "$Columns" ] 49&nbsp;  do 50&nbsp;    let "index = $row * $Rows + $column" 51&nbsp;    echo -n "${alpha[index]} "  # alpha[$row][$column] 52&nbsp;    let "column += 1" 53&nbsp;  done 54&nbsp; 55&nbsp;  let "row += 1" 56&nbsp;  echo 57&nbsp; 58&nbsp;done   59&nbsp; 60&nbsp;# 更简单的等价写法为:  61&nbsp;#     echo ${alpha[*]} | xargs -n $Columns 62&nbsp; 63&nbsp;echo 64&nbsp;} 65&nbsp; 66&nbsp;filter ()     # 过滤掉负的数组下标.  67&nbsp;{ 68&nbsp; 69&nbsp;echo -n "  "  # 产生倾斜.  70&nbsp;              # 解释一下, 这是怎么做到的.  71&nbsp; 72&nbsp;if [[ "$1" -ge 0 &#38;&#38;  "$1" -lt "$Rows" &#38;&#38; "$2" -ge 0 &#38;&#38; "$2" -lt "$Columns" ]] 73&nbsp;then 74&nbsp;    let "index = $1 * $Rows + $2" 75&nbsp;    # 现在, 按照旋转方向进行打印.  76&nbsp;    echo -n " ${alpha[index]}" 77&nbsp;    #           alpha[$row][$column] 78&nbsp;fi     79&nbsp; 80&nbsp;} 81&nbsp;   82&nbsp; 83&nbsp; 84&nbsp; 85&nbsp;rotate ()  #  将数组旋转45度 -- 86&nbsp;{          #+ 从左下角进行"平衡".  87&nbsp;local row 88&nbsp;local column 89&nbsp; 90&nbsp;for (( row = Rows; row &#62; -Rows; row-- )) 91&nbsp;  do       # 反向步进数组, 为什么?  92&nbsp; 93&nbsp;  for (( column = 0; column &#60; Columns; column++ )) 94&nbsp;  do 95&nbsp; 96&nbsp;    if [ "$row" -ge 0 ] 97&nbsp;    then 98&nbsp;      let "t1 = $column - $row" 99&nbsp;      let "t2 = $column"100&nbsp;    else101&nbsp;      let "t1 = $column"102&nbsp;      let "t2 = $column + $row"103&nbsp;    fi  104&nbsp;105&nbsp;    filter $t1 $t2   # 将负的数组下标过滤出来. 106&nbsp;                     # 如果你不做这一步, 将会怎样? 107&nbsp;  done108&nbsp;109&nbsp;  echo; echo110&nbsp;111&nbsp;done 112&nbsp;113&nbsp;#  数组旋转的灵感来源于Herbert Mayer所著的114&nbsp;#+ "Advanced C Programming on the IBM PC"的例子(第143-146页)115&nbsp;#+ (参见参考书目). 116&nbsp;#  由此可见, C语言能够做到的好多事情, 117&nbsp;#+ 用shell脚本一样能够做到. 118&nbsp;119&nbsp;}120&nbsp;121&nbsp;122&nbsp;#--------------- 现在, 让我们开始吧. ------------#123&nbsp;load_alpha     # 加载数组. 124&nbsp;print_alpha    # 打印数组.   125&nbsp;rotate         # 逆时钟旋转45度打印. 126&nbsp;#-----------------------------------------------------#127&nbsp;128&nbsp;exit 0129&nbsp;130&nbsp;# 这是有点做作, 不是那么优雅. 131&nbsp;132&nbsp;# 练习:133&nbsp;# -----134&nbsp;# 1)  重新实现数组加载和打印函数, 135&nbsp;#     让其更直观, 可读性更强. 136&nbsp;#137&nbsp;# 2)  详细地描述旋转函数的原理. 138&nbsp;#     提示: 思考一下倒序索引数组的实现. 139&nbsp;#140&nbsp;# 3)  重写这个脚本, 扩展它, 让不仅仅能够支持非正方形的数组. 141&nbsp;#     比如6 X 4的数组. 142&nbsp;#     尝试一下, 在数组旋转时, 做到最小"失真". </PRE></FONT></TD></TR></TABLE><HR></DIV><P>二维数组本质上其实就是一个一维数组, 		  只不过是添加了<EM>行</EM>和<EM>列</EM>的寻址方式, 		  来引用和操作数组的元素而已. 	</P><P>这里有一个精心制作的模拟二维数组的例子, 		请参考<AHREF="contributed-scripts.html#LIFESLOW">例子 A-10</A>. </P><P>--</P><P>还有两个使用脚本的更有趣的例子, 		 请参考:        <P></P><UL><LI><P><AHREF="commandsub.html#AGRAM2">例子 14-3</A>和<AHREF="contributed-scripts.html#HASHEX2">例子 A-23</A></P></LI></UL>     </P></DIV><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="list-cons.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="devproc.html"ACCESSKEY="N">下一页</A></TD></TR><TR><TDWIDTH="33%"ALIGN="left"VALIGN="top">列表结构</TD><TDWIDTH="34%"ALIGN="center"VALIGN="top"><AHREF="part4.html"ACCESSKEY="U">上一级</A></TD><TDWIDTH="33%"ALIGN="right"VALIGN="top">/dev和/proc</TD></TR></TABLE></DIV></BODY></HTML>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -