bash中的变量,就象PERL中的变量一样, 是无类型的, 或者话反过来说, PERL学了shell中的变量规则, 是弱类型的. <<Advanced Bash−Scripting Guide>>一书中有一章专门讲这个, 其实就我的使用经验来说, 这种特性是弊大于利...
#!/bin/bash # int.or.string.sh: Integer or string? a=2334 # Integer. let "a += 1" echo "a = $a " # a = 2335 echo # Integer, still. b=$ # Substitute "BB" for "23". # This transforms $b into a string. echo "b = $b" # b = BB35 declare .i b # Declaring it an integer doesn't help. echo "b = $b" # b = BB35 let "b += 1" # BB35 + 1 = echo "b = $b" # b = 1 echo c=BB34 echo "c = $c" # c = BB34 d=$ # Substitute "23" for "BB". # This makes $d an integer. echo "d = $d" # d = 2334 let "d += 1" # 2334 + 1 = echo "d = $d" # d = 2335 echo # What about null variables? e="" echo "e = $e" # e = let "e += 1" # Arithmetic operations allowed on a null variable? echo "e = $e" # e = 1#!/bin/bash # int.or.string.sh: Integer or string? a=2334 # Integer. let "a += 1 echo "a = $a " # a = 2335 echo # Integer, still. b=$ # Substitute "BB" for "23". # This transforms $b into a string. echo "b = $b" # b = BB35 declare .i b # Declaring it an integer doesn't help. echo "b = $b" # b = BB35 let "b += 1" # BB35 + 1 = echo "b = $b" # b = 1 ech c=BB3 echo "c = $c" # c = BB34 d=$ # Substitute "23" for "BB". # This makes $d an integer. echo "d = $d" # d = 2334 let "d += 1" # 2334 + 1 = echo "d = $d" # d = 2335 ech # What about null variables? e=" echo "e = $e" # e = let "e += 1" # Arithmetic operations allowed on a null variable? echo "e = $e" # e = 1 echo # Null variable transformed into an integer. # What about undeclared variables? echo "f = $f" # f = let "f += 1" # Arithmetic operations allowed? echo "f = $f" # f = 1 echo # Undeclared variable transformed into an integer. # Variables in Bash are essentially untyped. exit
echo # Null variable transformed into an integer. # What about undeclared variables? echo "f = $f" # f = let "f += 1" # Arithmetic operations allowed? echo "f = $f" # f = 1 echo # Undeclared variable transformed into an integer. # Variables in Bash are essentially untyped. exit 0
惨了, 原书的#注释在同一列上对的整整齐齐COPY到这里就成这样了. 写这种书用这种风格我是欣赏的, 讲究 实际, 用第一手的代码说话, 而且都经过测试. 下面是我今天写一个不足百生的SHELL脚本时碰到的变量方面的问题
declare -i i=0 while [ $i -lt $image_height ] do # 提取文件中的图象数据 let i = i+1 done
######## 中间经过苦干行, 根据我对循环变量的使用习惯, 用i作变量名. for i in c m y k do # 引用变量 $i, 企图得到 c m y k done 但此时的四次循环中每次我却都是取了个0. 为什么, 原因在于i变量一旦被声明为整型变量, 后续对它的赋值和一般的加减运算就有了一个整数取向. 如下: declare -i i=1 i=asdf echo $i #你得到的是0, 而且i=asdf 赋值是成功的, 用$?查看值为0 echo asdf | read i echo $i #得到的结果一样. 在不同场合下对i的赋值都是一样 let 'i = i + 1234asdf' echo $i #得到1234, 表达式中的1234asdf被当作字串, 与i做加减运算时被转换成数字1234, 这个地方不同的bash版本 #表现还不一样, 家里机器上的bash2.05.8(1)-release 会报错说 1234asdf太大了....
下面是使用BASH变量的小暗角: (1)declare -i var声明一个变量后不要再用这个变量做循环子变量, 除非它要遍历的元素全是整数. work-around: declare +i var, 或 unset var (2)declare -a 声明的数组变量引用时是这样的: echo $ #第一个元素 得到数组长度: echo $ 或 $ 但@, *并不可以手工展开 echo $ 取到的是第3个元素的值, 0,1,2类似于C语言中逗号表达式的次第求值. declare -a array=(1 2 3 '4 5' 6) 得到的数组是6个元素, 4和5分别是两个元素,''被提前展开. 要给一个元素赋值为'4 5'这个字符串, 需要单独赋值: ar[0]='4 5'
无法通过unset数组的的某个元素来把数组在此截断, 虽然这样想起来很直观, 比如原来10个元素的数组, 来个 unset ar[1] 现在长度就剩1了, 不然! 数组中可以有空洞, 即有些元素相当于NULL(NUL, NIL, NV)值. (3)普通变量也可以象数组变量一样被引用, 而数组变量也可以象普通变量一样被使用, 返回的是数组的第一个元素, 虽然这很不直观 普通变量被当作数组变量使用时, 数组变量的第一个元素的值就是那个普通变量的值 declare -i i=1234 echo $ #就是1234喽 i[1]=asdf #这里赋值同样会失败, i[1]值为0 所以上面那本书里说BASH的变量是untype的, 我觉得说成弱类型的更合适, 虽然它比有些弱类型更弱.
(4)正则表达式中的. 能不能代表非ASCII的二进制数据? 这是个问题, 但处理二进制数据不是正则表达式的主项. 所以关于文本工具处理二进制数据的讨论极少, 下面是我遇到的问题: var=$(echo 4100000000000 | xxd -r -ps) var的值是A, 没有后面的0. 其实不光是00, 换成01也一样会被SHELL处理掉. echo 4100000000000 | xxd -r -ps | sed 's#\(A\).*##' | xxd -g1 结尾的0不会被处理掉, 也就是说. 不能表示\n之外, 还不能表示00, 但奇怪的是: echo 4100000000000 | xxd -r -ps | sed 's#\(A\)[^a]*##' | xxd -g1 这样取一个简单的补集却又能把这个字符给消除掉. 我在几乎所有的正则表达式表述中都看到.代表除\n之外的所有(是不是字符?). 但sed 至少有这个很不直观的地方, 我不认为有个官方文档中有意识地定义了这一点.
|