shell教程
OutOfMemory.CN技术专栏-> shell-> shell教程-> 第三十四章. Bash, 版本 2 和 3

第三十四章. Bash, 版本 2 和 3

当前运行在你的机器里的Bash版本号是版本2.xx.y或3.xx.y.bash$echo$BASH_VERSION2.05.b.0(1)-release经典的Bash版本2编程语言升级版增加了数组变量,[1]字符串和参数扩

当前运行在你的机器里的Bash版本号是版本 2.xx.y 或 3.xx.y.

 bash$ echo $BASH_VERSION
 2.05.b.0(1)-release
 	      
经典的Bash版本2编程语言升级版增加了数组变量, [1] 字符串和参数扩展, 和间接变量引用的更好的方法,及其他的属性.


例子 34-1. 字符串扩展

#!/bin/bash

# 字符串扩展.
# Bash版本2引入的特性.

#  具有$'xxx'格式的字符串
#+ 将会解释里面的标准的转义字符.

echo $'Ringing bell 3 times \a \a \a'
     # 可能在一些终端只能响铃一次.
echo $'Three form feeds \f \f \f'
echo $'10 newlines \n\n\n\n\n\n\n\n\n\n'
echo $'\102\141\163\150'   # Bash
                           # 八进制相等的字符.

exit 0


例子 34-2. 间接变量引用 - 新方法

#!/bin/bash

# 间接变量引用.
# 这有点像C++的引用属性.


a=letter_of_alphabet
letter_of_alphabet=z

echo "a = $a"           # 直接引用.

echo "Now a = ${!a}"    # 间接引用.
# ${!variable} 形式比老的"eval var1=\$$var2"更高级

echo

t=table_cell_3
table_cell_3=24
echo "t = ${!t}"                      # t = 24
table_cell_3=387
echo "Value of t changed to ${!t}"    # 387

#  这在用来引用数组或表格的成员时非常有用,
#+ 或用来模拟多维数组.
#  如果有可索引的选项 (类似于指针运算)
#+ 会更好. 唉.

exit 0


例子 34-3. 使用间接变量引用的简单数据库应用

#!/bin/bash
# resistor-inventory.sh
# 使用间接变量引用的简单数据库应用.

# ============================================================== #
# 数据

B1723_value=470                                   # 值
B1723_powerdissip=.25                             # 是什么
B1723_colorcode="yellow-violet-brown"             # 色彩带宽
B1723_loc=173                                     # 它们存在哪儿
B1723_inventory=78                                # 有多少

B1724_value=1000
B1724_powerdissip=.25
B1724_colorcode="brown-black-red"
B1724_loc=24N
B1724_inventory=243

B1725_value=10000
B1725_powerdissip=.25
B1725_colorcode="brown-black-orange"
B1725_loc=24N
B1725_inventory=89

# ============================================================== #


echo

PS3='Enter catalog number: '

echo

select catalog_number in "B1723" "B1724" "B1725"
do
  Inv=${catalog_number}_inventory
  Val=${catalog_number}_value
  Pdissip=${catalog_number}_powerdissip
  Loc=${catalog_number}_loc
  Ccode=${catalog_number}_colorcode

  echo
  echo "Catalog number $catalog_number:"
  echo "There are ${!Inv} of [${!Val} ohm / ${!Pdissip} watt] resistors in stock."
  echo "These are located in bin # ${!Loc}."
  echo "Their color code is \"${!Ccode}\"."

  break
done

echo; echo

# 练习:
# ---------
# 1) 重写脚本,使其从外部文件里读数据.
# 2) 重写脚本,用数组代替间接变量引用
#
#    用数组会更简单明了


# 注:
# -----
#  Shell脚本除了最简单的数据应用,其实并不合适数据库应用,
#+ 它过多地依赖实际工作的环境和命令.
#  写数据库应用更好的还是用一门自然支持数据结构的语言,
#+ 如 C++ 或 Java (或甚至是 Perl).

exit 0


例子 34-4. 用数组和其他的小技巧来处理四人随机打牌

#!/bin/bash

# Cards:
# 处理四人打牌.

UNPICKED=0
PICKED=1

DUPE_CARD=99

LOWER_LIMIT=0
UPPER_LIMIT=51
CARDS_IN_SUIT=13
CARDS=52

declare -a Deck
declare -a Suits
declare -a Cards
#  用一个三维数据来描述数据会更容易实现也更明了一些。
#
#  可能Bash将来的版本会支持多维数组.


initialize_Deck ()
{
i=$LOWER_LIMIT
until [ "$i" -gt $UPPER_LIMIT ]
do
  Deck[i]=$UNPICKED   # 把整副牌的每张牌都设为没人持牌.
  let "i += 1"
done
echo
}

initialize_Suits ()
{
Suits[0]=C #梅花
Suits[1]=D #方块
Suits[2]=H #红心
Suits[3]=S #黑桃
}

initialize_Cards ()
{
Cards=(2 3 4 5 6 7 8 9 10 J Q K A)
# 另一种初始化数组的方法.
}

pick_a_card ()
{
card_number=$RANDOM
let "card_number %= $CARDS"
if [ "${Deck[card_number]}" -eq $UNPICKED ]
then
  Deck[card_number]=$PICKED
  return $card_number
else
  return $DUPE_CARD
fi
}

parse_card ()
{
number=$1
let "suit_number = number / CARDS_IN_SUIT"
suit=${Suits[suit_number]}
echo -n "$suit-"
let "card_no = number % CARDS_IN_SUIT"
Card=${Cards[card_no]}
printf %-4s $Card
# 优雅地打印各张牌.
}

seed_random ()  # 随机产生牌上数值的种子.
{               # 如果你没有这么做会有什么发生?
seed=`eval date +%s`
let "seed %= 32766"
RANDOM=$seed
#  其他的产生随机用的种子的方法还有什么W?
#
}

deal_cards ()
{
echo

cards_picked=0
while [ "$cards_picked" -le $UPPER_LIMIT ]
do
  pick_a_card
  t=$?

  if [ "$t" -ne $DUPE_CARD ]
  then
    parse_card $t

    u=$cards_picked+1
    # 改回1步进的索引(临时的). 为什么?
    let "u %= $CARDS_IN_SUIT"
    if [ "$u" -eq 0 ]   # 内嵌的 if/then 条件测试.
    then
     echo
     echo
    fi
    # Separate hands.

    let "cards_picked += 1"
  fi
done

echo

return 0
}


# 结构化编程:
# 整个程序逻辑模块化.

#================
seed_random
initialize_Deck
initialize_Suits
initialize_Cards
deal_cards
#================

exit 0



# 练习 1:
# 把这个脚本完整地做注释.

# 练习 2:
# 增加一个处理例程 (函数) 来以花色排序打印出每个人手中的牌.
# 如果你高兴,可增加你喜欢的各种酷的代码.

# 练习 3:
# 简化和理顺脚本的逻辑.

[1]

Chet Ramey 承诺会在Bash的未来版本中实现关联数组(associative arrays) (一个Perl特性). 到了版本3,这个特性还没有实现.

© 内存溢出 OutOfMemory.CN