第八章 操作符和相关主题
8.1 操作符
等号操作符
= 变量赋值(初始化或修改变量的值)
无论在算术运算还是字符串运算中,都是赋值语句
#"="后边不能有空格
var=27
category=minerals
注意:不要和"="test操作符混淆
算术操作符
+ 加法
- 减法
* 乘法
/ 除法
** 幂运算
let "z=5**3"
echo "z = $z" #z = 125
% 取模
expr 5 % 3 #2
Example 8.1 最大公约数
#!/bin/bash
#gcd.sh :最大公约数
#最大公约数就是2个数能够同时整除的最大的数
#Euclid's算法采用连续除法
#在每个循环中被除数<--除数;除数<--余数;直到余数=0
#在最后的循环中The gcd=被除数
#参数检查
ARGS=2
E_BADARGS=65
if [ $# -ne "$ARGS" ];then
echo "用法:`basename $0` 第一个整数 第二个整数"
exit $E_BADARGS
fi
#练习:确保参数都是整数
E_NOINT=66
FIRST_NUMBER=`echo $1%1 |bc`
SECOND_NUMBER=`echo $2%1 |bc`
if [ "$FIRST_NUMBER" == 0 -a "$SECOND_NUMBER" == 0 ]
then :
else
echo "Usage:`basename $0` 第一个整数 第二个整数"
exit $E_NOINT
fi
gcd() {
dividend=$1 #随便给值
divisor=$2
remainder=1 #如果在循环中使用未初始化的变量,那将在第一次的循环中产生一个错误消息
until [ "$remainder" -eq 0 ]
do
let "remainder = $dividend % $divisor"
dividend=$divisor
divisor=$remainder
done
}
gcd $1 $2
echo;echo "GCD of $1 and $2 = $dividend";echo
exit 0
+= 加等于(通过常量增加变量)
let "var += 5" #var在本身的基础上增加5
-= 减等于
*= 乘等于
let "var *= 4"
/= 除等于
%= 取模赋值,算术操作经常使用expr或者let表达式
Example 8.2 使用算术操作符
#!/bin/bash
#
n=1
echo -n $n
let "n = $n +1" #let "n = n +1" 这么写也可以
echo -n $n
: $((n = $n +1)) #:是必须的,如果没有:,Bash将尝试把$((n = $n +1))解释成一个命令
echo -n $n
(( n = n + 1 ))
#对于上边的方法的一个简单的选择
n=$(($n+1))
echo -n $n
: $[n = $n + 1] #:是必须的
echo -n $n
n=$[$n +1]
echo -n $n
#现在来个C分格的增量操作
let "n++"
echo -n "$n"
((n++))
echo -n "$n"
: $((n++))
echo -n "$n"
: $[n++]
echo -n "$n"
echo
exit 0
注意:在Bash中的整型变量事实上是32位的,范围是-2147483648到2147483647,如果超过这个范围进行算术操作的话,会报错
注意:Bash并不能理解浮点运算。它会把包含小数点看做字符串。如果真想做浮点运算的话,使用bc(见12.8节),bc可以进行浮点运算或调用数学库函数
位操作符
位操作符在shell脚本中极少使用。它最主要的用途看起来就是操作和test从sockets中读出的变量。"Bit flipping"与编译语言的联系很紧密,比如c/c++,在这种语言中它可以运行的足够块
<< 左移一位(每次左移都将乘2)
<<= 左移几位,=后边将给出左移几位
let "var <<=2" 就是左移2(就是乘4)
>> 右移1位(每次右移都将除2)
>>= 右移几位
& 按位与
&= 按位与赋值
| 按位或
|= 按位或赋值
~ 按位非
! 按位否
^ 按位异或XOR
^= 异或赋值
逻辑操作
&& 逻辑与
if [ $condition1 ] && [ $condition2 ] #与if [ $condition1 -a $condition2]相同
#if [[ $condition1 && $condition2 ]] 也可以
#注意:&&不允许出现在[...]中
|| 逻辑或
if [ $condition1 ] || [ $condition2 ] #与if [ $condition1 -o $condition2]相同
#if [[ $condition1 || $condition2 ]] 也可以
#注意:||不允许出现在[...]中
Example 8.3 使用&&和||进行混合状态的test
#!/bin/bash
#
a=24
b=47
if [ $a -eq 24 ] && [ $b -eq 47 ];then
echo "Test #1 succeeds."
else
echo "Test #1 fails."
fi
#尝试一(报错)
if [ $a -eq 24 && $b -eq 47 ];then
echo "Test 尝试一 succeeds."
else
echo "Test 尝试一 fails."
fi
#尝试二(可以使用)
if [[ $a -eq 24 && $b -eq 47 ]];then
echo "Test 尝试二 succeeds."
else
echo "Test 尝试二 fails."
fi
if [ $a -eq 89 ] || [ $b -eq 47 ];then
echo "Test #2 succeeds."
else
echo "Test #2 fails."
fi
#-a和-o选项提供了一种可选的混合test方法
if [ $a -eq 24 -a $b -eq 47 ];then
echo "Test #3 succeeds."
else
echo "Test #3 fails."
fi
if [ $a -eq 89 -o $b -eq 47 ];then
echo "Test #4 succeeds."
else
echo "Test #4 fails."
fi
a=rhino
b=crocodile
if [ "$a" = rhino ] && [ "$b" = crocodile ];then
echo "Test #5 succeeds."
else
echo "Test #5 fails."
fi
exit 0
混杂操作
, 逗号操作符
逗号操作符可以连接2个或多个算术运算。所有的操作都会被执行,但是只有最后一个操作作为结果
let "t1=((5+3,7-1,15-4))"
echo $t1 #11
let "t2=((a=9,15/3))"
echo "t2=$t2 a=$a" #t2=5 a=9
","主要用在for循环中,具体见Example 10.12.
8.2 数字常量
shell脚本默认都是将数字作为10进制处理,除非这个数字某种特殊的标记法或者前缀开头。以0开头就是8进制。以0x开头就是16进制。使用BASE#NUMBER这种形式可以表示其他进制表示法
Example 8.4 数字常量的处理
#!/bin/bash
#numbers.sh:数字常量的几种不同的表示法
#10进制:默认
let "dec=32"
echo "decimal number=$dec" #32
#8进制:以0开头
let "oct=032"
echo "octal number=$oct" #26
#表达式的结果用10进制表示
#16进制表示:数字以0x或者0X开头
let "hex=0x32"
echo "hexadecimal number=$hex" #50
#其它进制:BASE#NUMBER
#2-64进制都可以
#NUMBER必须在BASE的范围内
let "bin=2#11100111001101"
echo "binary number=$bin" #331181
let "b32=32#77"
echo "base-32 number=$b32" #231
let "b64=64#@_"
echo "base-64 number=$b64" #4031
#这种64进制的表示法中的每位数字都必须在64进制表示法的限制字符内
#10个数字+26个小写字母+26个大写字母+@+_
echo
echo $((36#zz)) $((2#10101010)) $((16#AF16)) $((53#1aA)) #1295 170 44822 3375
#注意:如果使用的每位数字超出了这个进制表示法规定字符的范围的话,将会给出一个错误。
let "bad_oct=081"
#-bash: let: bad_oct=081: value too great for base (error token is "081")
#值对于base太大(错误标记是“081”)
exit 0