Bash 基本运算和变量

注意:变量尽量用双引号引起来
对于值为非空的变量无所谓,对于值为空的变量,很可能出问题

一、expr 为内置命令,只对整数进行运算(注意空格)

1.1 四则运算(只有 + - * / % ± 这些符号可用)

zds@ubuntu:~$ expr 8 + 9
17
zds@ubuntu:~$ expr -9 + 3
-6
zds@ubuntu:~$ expr 3 \* 22  # 乘号需转义
66
zds@ubuntu:~$ expr 22 % 9  # 取余数
4
zds@ubuntu:~$ expr 123 / 12 - 3
7
zds@ubuntu:~$ a=5
zds@ubuntu:~$ expr $a / -2
-2

1.2 逻辑运算:或 |&!(前两者须转义,后者须配合 = 使用)
注意命令的返回值(即运算结果)和退出状态码的区别

zds@ubuntu:~$ expr 9 \| 3  # 两者都不为 0 结果取前者,退出状态码为 0
9
zds@ubuntu:~$ expr 3 \| 9
3
zds@ubuntu:~$ expr 0 \| 0  # 若两个都为 0 结果为 0,退出状态码为 1
0
zds@ubuntu:~$ expr 0 \| 5  # 若有一个为 0 结果取另一个的值,退出状态码为 0
5
zds@ubuntu:~$ expr 5 \| 0
5
zds@ubuntu:~$ expr 4 \& 9  # 两者都不为 0 结果取前者,退出状态码为 0
4
zds@ubuntu:~$ expr 9 \& 4
9
zds@ubuntu:~$ expr 0 \& 0  # 两者若有一个为 0 结果即为 0,退出状态码为 1
0
zds@ubuntu:~$ expr 111 \& 0
0
zds@ubuntu:~$ expr 0 \& 111
0
zds@ubuntu:~$ expr 9 != 3  # 逻辑为真结果是 1,退出状态码为 0
1
zds@ubuntu:~$ expr 9 != 7 + 2  # 逻辑为假结果是 0,退出状态码为 1
0
zds@ubuntu:~$ expr 9 = 3 \* 3  # 逻辑为真结果是 1,退出状态码为 0
1

1.3 关系运算<> 须转义)
注意:下面说的都是运算结果(即命令返回值),而不是退出状态码

zds@ubuntu:~$ expr 9 \< 9  # 关系为假结果是 0
0
zds@ubuntu:~$ expr 8 \>= 3 \* 3
0
zds@ubuntu:~$ expr 8 \>= 2 \* 3  # 关系为真结果是 1
1
zds@ubuntu:~$ expr -45 / 11 = -4  # 一个等号和俩等号都是判断左右是否相等
1
zds@ubuntu:~$ expr 3 == 3  # macOS 中不能使用俩等号
1

二、(( )) 依然只对整数进行运算

相较 expr 要人性化,不必转义特殊符号,不必加空格

zds@ubuntu:~$ ((a=(2+3)*4))  # 可用使用括号
zds@ubuntu:~$ echo $a
20
zds@ubuntu:~$ a=0
zds@ubuntu:~$ echo $a
0
zds@ubuntu:~$ ((a+=3))
zds@ubuntu:~$ echo $a
3
zds@ubuntu:~$ ((a=a*4))
zds@ubuntu:~$ echo $a
12
zds@ubuntu:~$ ((a/=5))
zds@ubuntu:~$ echo $a
2
zds@ubuntu:~$ ((a++))  # 加 1
zds@ubuntu:~$ echo $a
3
zds@ubuntu:~$ ((a--))  # 减 1
zds@ubuntu:~$ echo $a
2
zds@ubuntu:~$ echo $((9*-4/6))  # 固定写法
-6
zds@ubuntu:~$ echo $((3**4))  # 幂运算
81
zds@ubuntu:~$ echo $((2#101))  # 把井号后面的数当作二进制来处理,将之转换为十进制
5

三、let(( )) 一样

zds@ubuntu:~$ a=0
zds@ubuntu:~$ let a-=9
zds@ubuntu:~$ echo $a
-9
zds@ubuntu:~$ let a=(89-33)*7
zds@ubuntu:~$ echo $a
392

四、declare -i 使变量数值化

zds@ubuntu:~$ num=2+3
zds@ubuntu:~$ echo $num
2+3
zds@ubuntu:~$ declare -i num  # 使 num 变量的值数值化
zds@ubuntu:~$ echo $num
2+3
zds@ubuntu:~$ num=9/4
zds@ubuntu:~$ echo $num
2
zds@ubuntu:~$ num=ok  # 赋值字符串,无法计算,结果为 0
zds@ubuntu:~$ echo $num
0

五、bc 属于外部命令,可用 sudo apt install bc 安装

5.1 bc 可运算小数
结果小数位数等于算术式中数值的小数位数的最大值

zds@ubuntu:~$ echo '2+2' | bc
4
zds@ubuntu:~$ echo '(3+2.4)*7' | bc  
37.8
zds@ubuntu:~$ echo '(-36%7)**3--5.5' | bc  # 不可连续两个减号
(standard_in) 1: syntax error
zds@ubuntu:~$ echo '(-36%7)**3-(-5.5)' | bc  # 不可进行幂运算
(standard_in) 1: syntax error
zds@ubuntu:~$ echo '(-36%7)*3-(-5.5)' | bc
2.5

5.2 交互界面,按 Ctrl + D 退出

zds@ubuntu:~$ bc
bc 1.06.95
Copyright 1991-1994, 1997, 1998, 2006 Free Software Foundation, Inc.
This is free software with ABSOLUTELY NO WARRANTY.
For details type `warranty'. 
(8*8-9)/3.3
16
scale=2  # 默认保留 0 位小数,设置小数位数为 2,只对乘除有效
(8*8-9)/3.3
16.66

六、条件判断

6.1 Shell 中的 test 命令用于检查某个条件是否成立,它可以进行数值、字符和文件三个方面的测试

6.1.1 test 比较两个整数值,[ ] 等同于 test,注意只能比较一位数
-gt \> 大于,-lt \< 小于,-ge 大于等于,-le 小于等于
-eq = == 等于,-ne != 不等于:

mcdx@ubuntu:~$ test 2 -gt 3  
mcdx@ubuntu:~$ echo $?  # 获取上次命令的返回值,结果为假返回值为 1
1
mcdx@ubuntu:~$ test 34 -lt 91
mcdx@ubuntu:~$ echo $?  
0
mcdx@ubuntu:~$ [ 3 -eq 3 ]
mcdx@ubuntu:~$ echo $?
0
mcdx@ubuntu:~$ read a b
1 1
mcdx@ubuntu:~$ if [ $a == $b ]; then echo '俩数相等'; fi
俩数相等
mcdx@ubuntu:~$ read a b 
1 2
mcdx@ubuntu:~$ if [ $a -le $b ]; then echo 'a 小于等于 b'; fi
a 小于等于 b
mcdx@ubuntu:~$ read a b
1 '1'
mcdx@ubuntu:~$ if [ $a = $b ]; then echo '俩数相等'; else echo '俩数不等'; fi
俩数不等

6.1.2 test [ ] 判断字符串
-eq = == 等于,-ne != 不等于,-n 长度不为零,-z 长度为零:

mcdx@ubuntu:~$ read a

mcdx@ubuntu:~$ echo $a  # 体现了引用变量加双引号的重要性

mcdx@ubuntu:~$ if [ -n $a ]; then echo '长度不为零'; else echo '长度为零'; fi
长度不为零
mcdx@ubuntu:~$ if [ -n "$a" ]; then
> echo '长度不为零'; else
> echo '长度为零'; fi
长度为零
mcdx@ubuntu:~$ read a

# -n 可省略
mcdx@ubuntu:~$ if [ "$a" ]; then echo '不为空'; else echo '为空'; fi  
为空  
mcdx@ubuntu:~$ read a
12
mcdx@ubuntu:~$ if [ "$a" ]; then echo '不为空'; else echo '为空'; fi
不为空

6.1.3 test [ ] 判断文件
-d 是目录,-e 文件存在,-r 文件可读,-w 文件可写,-x 文件可执行
-f 普通文件,-s 文件大小不为零,-o 或逻辑,-a 与逻辑
-O 当前用户是文件的拥有者(以上这些,双中括号不能用):

mcdx@ubuntu:~$ ls
Desktop  Documents  Downloads  git  simpledu  test  test.sh
mcdx@ubuntu:~$ [ -e test.sh ]; echo $?
0
mcdx@ubuntu:~$ test -d git; echo $?
0
mcdx@ubuntu:~$ test -d test.sh; echo $?
1
mcdx@ubuntu:~$ [ -O test.sh ]; echo $?
0
mcdx@ubuntu:~$ [ -e test.sh -o -e xxx ]; echo $?
0
mcdx@ubuntu:~$ [ -e test.sh -a -e xxx ]; echo $?
1

6.2 [[ ]] 是比较高级的判断方法(说是高级,其实用法之复杂也让人作呕)
-gt > 大于,-lt < 小于(<> 只能比较一位数字的大小)
-ge 大于等于,-le 小于等于,-eq = == 等于,-ne != 不等于
-n 长度不为零,-z 长度为零,&& 与,|| 或:

shiyanlou:~/ $ [[ 23 < 123 ]]; echo $?  
1
shiyanlou:~/ $ [[ 23 < 24 ]]; echo $?  
0
zds@ubuntu:~$ a=1; b=2; c=1
# 不加 $ 符号也可以,但尽量加上,双引号也尽量加上
zds@ubuntu:~$ [[ a < b ]]; echo $?  
0
zds@ubuntu:~$ [[ a > b ]]; echo $?
1
zds@ubuntu:~$ [[ $a < $b ]]; echo $?
0
zds@ubuntu:~$ [[ $a > $b ]]; echo $?
1
zds@ubuntu:~$ [[ $a <= $b ]]; echo $?  # 这种写法不行,单中括号里也不行
bash: 条件表达式中有语法错误
bash: `$b' 附近有语法错误
zds@ubuntu:~$ [[ $a -lt $b ]]; echo $?
0
zds@ubuntu:~$ [[ $a -le $b ]]; echo $?
0
zds@ubuntu:~$ [[ $a = $c ]]; echo $?
0
zds@ubuntu:~$ [[ $a = $b ]]; echo $?
1
zds@ubuntu:~$ [[ $a == $c ]]; echo $?
0
zds@ubuntu:~$ [[ $a -eq $c ]]; echo $?
0
zds@ubuntu:~$ [[ $a != $c ]]; echo $?
1
zds@ubuntu:~$ [[ $a -ne $b ]]; echo $?
0
zds@ubuntu:~$ [[ -n $a ]]; echo $?
0
zds@ubuntu:~$ declare d
zds@ubuntu:~$ [[ -n $d ]]; echo $?
1
zds@ubuntu:~$ [[ -z $d ]]; echo $?
0
zds@ubuntu:~$ e=hello
zds@ubuntu:~$ [[ $e = hell? ]]; echo $?  # 问号通配符也能用(别的通配符不行)
0
zds@ubuntu:~$ [[ $e == hell? ]]; echo $?
0
zds@ubuntu:~$ [[ $e -eq hello ]]; echo $?  # 不可以用 -eq 判断非数值
0
zds@ubuntu:~$ [[ $e -eq hellooo ]]; echo $?
0
zds@ubuntu:~$ [[ $e = worl? ]]; echo $?
1
zds@ubuntu:~$ [[ -n $e && 3 > 2 ]]; echo $?  # 与
0
zds@ubuntu:~$ [[ -n $e && 3 = 2 ]]; echo $?
1
zds@ubuntu:~$ [[ -n $e || 3 = 2 ]]; echo $?  # 或
0

=~ 使用正则表达式,前者包含后者,表达式即为真。几个常用的符号:
^ 匹配字符串的开始处,$ 匹配字符串的结尾处
+ 匹配一个或多个前面的字符,? 匹配 0 个或 1 个前面的字符
. 匹配任意一个字符

mcdx@ubuntu:~$ a=assss
mcdx@ubuntu:~$ if [[ $a =~ ^as+ ]]; then echo 'ok'; else echo 'not ok'; fi
ok
mcdx@ubuntu:~$ if [[ $a =~ ^as ]]; then echo 'ok'; else echo 'not ok'; fi
ok
mcdx@ubuntu:~$ if [[ $a =~ ss ]]; then echo 'ok'; else echo 'not ok'; fi
ok
mcdx@ubuntu:~$ if [[ $a =~ sst ]]; then echo 'ok'; else echo 'not ok'; fi
not ok
mcdx@ubuntu:~$ [[ helloworld =~ world$ ]]; echo $?
0
mcdx@ubuntu:~$ [[ helloworld =~ worl$ ]]; echo $?
1
mcdx@ubuntu:~$ [[ abc =~ a.c ]]; echo $?
0
mcdx@ubuntu:~$ [[ abc =~ a.d ]]; echo $?
1

七、随机数

7.1 $RANDOM 可以生成 0-32767 的随机数
它不是一个变量,是一个内置的函数:

mcdx@ubuntu:~$ echo $RANDOM
32058
mcdx@ubuntu:~$ echo $RANDOM
170
mcdx@ubuntu:~$ echo $RANDOM
17302
mcdx@ubuntu:~$ expr $RANDOM / 222
54

7.2 此外,还可以使用 shuf 生成随机数
-i 指定随机数值的范围,-n 指定随机数的数量

mcdx@ubuntu:~$ shuf -i 1-10 -n 3
1
9
2
mcdx@ubuntu:~$ shuf -i 100-1000 -n 4
835
460
454
599

你可能感兴趣的:(Bash 基本运算和变量)