bash暗黑破坏神(1)
时间:2005-09-03 来源:slimzhao
<<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=${a/23/BB} # 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=${c/BB/23} # 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=${a/23/BB} # 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=${c/BB/23} # 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 ${array[0]} #第一个元素
得到数组长度:
echo ${#array[@]} 或 ${#array[*]} 但@, *并不可以手工展开
echo ${#array[0,1,2]} 取到的是第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 ${i[0]} #就是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).*#1#' | xxd -g1
结尾的0不会被处理掉, 也就是说. 不能表示 之外, 还不能表示00, 但奇怪的是:
echo 4100000000000 | xxd -r -ps | sed 's#(A)[^a]*#1#' | xxd -g1
这样取一个简单的补集却又能把这个字符给消除掉. 我在几乎所有的正则表达式表述中都看到.代表除 之外的所有(是不是字符?).
但sed 至少有这个很不直观的地方, 我不认为有个官方文档中有意识地定义了这一点.