Linux Shell 算术运算
米扑博客总结了 Bash shell 的算术运算有四种方式:
1、使用外部程式 expr (不支持乘幂、异或)
1)控制台命令行
# r=`expr 10 + 6` # 加法 # echo $r 16 # r=`expr 10 - 6` # 减法 # echo $r 4 # r=`expr 10 \* 6` # 乘法 # echo $r 60 # r=`expr 10 / 6` # 除法(整除) # echo $r 1 # r=`expr 10 % 6` # 取余 # echo $r 4
2)脚本语言编程
#!/bin/bash # mimvp.com 2014.10.10 ## 1. expr , 不支持乘幂、异或 function mimvp_cal_expr() { m=10 n=6 result=`expr $m + $n` # 加法 16 echo ${result} result=`expr $m - $n` # 减法 4 echo ${result} result=`expr $m \* $n` # 乘法 60 echo ${result} result=`expr $m / $n` # 除法 1 echo ${result} result=`expr $m % $n` # 取余 4 echo ${result} } mimvp_cal_expr
expr 字符串操作
expr 除了可以用于算术运算外,还可以用作字符串的截取子串
1)length 获取字符串的长度
格式:expr length "${str}"
str="1234567890" # 1.1 length 获取字符串长度 str_length=`expr length ${str}` # expr str_length=`echo ${str} | awk '{print length}'` # awk str_length=${#str} # ${} echo "str_length: ${str_length}" # 10
2)index 获取子串在字符串中出现的下标,未匹配返回0
格式:expr index ${str} "substr"
str="1234567890" # 1.2 index 获取字串出现的下标 str_index=`expr index ${str} "567"` # 下标从1算起, 匹配子串中任意字符最先出现的位置, 返回5 str_index=`expr index ${str} "765"` # 下标从1算起, 匹配子串中任意字符最先出现的位置, 返回5 str_index=`expr index ${str} "768"` # 下标从1算起, 匹配子串中任意字符最先出现的位置, 返回6 str_index=`expr index ${str} "abc"` # 未匹配, 返回0 echo "str_index: ${str_index}"
3)substr 截取子串,下标从1算起
格式:expr substr ${str} start [length]
str="1234567890" # 1.3 substr 截取获得子串 str_substr=`expr substr ${str} 5 3` # expr 下标从1算起, 从第5位截取长度为3, 返回567 str_substr=`echo ${str} | awk '{print substr($0,5,3)}'` # awk 下标从1算起, 从第5位截取长度为3, 返回567 str_substr=${str:5:3} # ${} 下标从0算起, 从第5位截取长度为3, 返回678 echo "str_substr: ${str_substr}"
4)match 匹配获取子串的长度, 匹配不到则返回0
格式:expr match ${str} substr
str="1234567890" # 1.4 match 匹配获取子串的长度, 匹配不到则返回0 str_match=`expr match ${str} 123` # 从第一个字母开始匹配, 返回匹配到的字串长度, 返回3 str_match=`expr match ${str} .*8` # 从第一个字母开始匹配, 正则表达式匹配到8结束, 返回8 str_match=`expr match ${str} 456` # 从第一个字母开始匹配, 子串456不是开始字母, 匹配失败, 返回0 echo "str_match: ${str_match}"
2、使用 $(( )) (推荐)
$[] 和 $(()) 使用完全是一样的
1)控制台命令行
# echo $(( 10 + 6 )) # 加法 16 # echo $(( 10 - 6 )) # 减法 4 # echo $(( 10 * 6 )) # 乘法 60 # echo $(( 10 ** 6 )) # 乘幂 1000000 # echo $(( 10 ^ 6 )) # 异或 12 (二进制 1010^0110 1100 12 # echo $(( 10 / 6 )) # 除法 1 # echo $(( 10 % 6 )) # 取余 4
2)脚本语言编程
#!/bin/bash # mimvp.com 2014.10.10 ## 2. $(()) , 用法完全等同于$[] function mimvp_cal_dollar() { m=10 n=6 result=$(( $m + $n )) # 加法 16 result=$(( m + n )) # 加法 16 echo ${result} result=$(( m - n )) # 减法 4 echo ${result} result=$(( m * n )) # 乘法 60 echo ${result} result=$(( m ** n )) # 乘幂 1000000 echo ${result} result=$(( m ^ n )) # 异或 12 (二进制 1010^0110 1100 echo ${result} result=$(( m / n )) # 除法 1 echo ${result} result=$(( m % n )) # 取余 4 echo ${result} } mimvp_cal_dollar
3、使用 $[ ] (推荐)
$[] 和 $(()) 使用完全是一样的
1)控制台命令行
# echo $[ 10 + 6 ] # 加法 16 # echo $[ 10 - 6 ] # 减法 4 # echo $[ 10 * 6 ] # 乘法 60 # echo $[ 10 ** 6 ] # 乘幂 1000000 # echo $[ 10 ^ 6 ] # 异或 12 (二进制 1010^0110 1100 12 # echo $[ 10 / 6 ] # 除法 1 # echo $[ 10 % 6 ] # 取余 4
2)脚本语言编程
#!/bin/bash # mimvp.com 2014.10.10 ## 3. $[] , 用法完全等同于$(()) function mimvp_cal_square() { m=10 n=6 result=$[ $m + $n ] # 加法 16 result=$[ m + n ] # 加法 16 echo ${result} result=$[ m - n ] # 减法 4 echo ${result} result=$[ m * n ] # 乘法 60 echo ${result} result=$[ m ** n ] # 乘幂 1000000 echo ${result} result=$[ m ^ n ] # 异或 12 (二进制 1010^0110 1100 echo ${result} result=$[ m / n ] # 除法 1 echo ${result} result=$[ m % n ] # 取余 4 echo ${result} } mimvp_cal_square
4、使用 let 命令
1)控制台命令行
# let "result = 10 + 6" # 加法 # echo $result 16 # let "result = 10 - 6" # 减法 # echo $result 4 # let "result = 10 * 6" # 乘法 # echo $result 60 # let "result = 10 ** 6" # 乘幂 # echo $result 1000000 # let "result = 10 ^ 6" # 异或 12 (二进制 1010^0110 1100 # echo $result 12 # let "result = 10 / 6" # 除法 # echo $result 1 # let "result = 10 % 6" # 取余 # # echo $result 4
2)脚本语言编程
#!/bin/bash # mimvp.com 2014.10.10 ## 4. let function mimvp_cal_let() { m=10 n=6 let "result = $m + $n" # 加法 16 let "result = m + n" # 加法 16 echo ${result} let "result = m - n" # 减法 4 echo ${result} let "result = m * n" # 乘法 60 echo ${result} let "result = m ** n" # 乘幂 1000000 echo ${result} let "result = m ^ n" # 异或 12 (二进制 1010^0110 1100 echo ${result} let "result = m / n" # 除法 1 echo ${result} let " result = m % n " # 取余 4 echo ${result} } mimvp_cal_let
5、bc 命令,高精度小数运算
bc命令是一种高精度的计算语言,本身提供了一些语法结构,如条件判断、循环、进制转换等,很强大的。
上面介绍的 expr、let、$(())、$[] 等只支持整数运算,但对于浮点运算就无能为力了。
下面介绍的 bc、dc、awk 都支持浮点计算。
# which bc dc awk /usr/bin/bc /usr/bin/dc /usr/bin/awk
1)控制台命令行(交互式)
bc 命令帮助:
# bc --help usage: bc [options] [file ...] -h --help print this usage and exit -i --interactive force interactive mode -l --mathlib use the predefined math routines -q --quiet don't print initial banner -s --standard non-standard bc constructs are errors -w --warn warn about non-standard bc constructs -v --version print version information and exit
bc 命令的几个常用参数:
-i 强制交互模式; -l 小写的L,使用bc的内置库,bc里有一些数学库,对三角计算等非常实用; -q 进入bc交互模式时不再输出版本等多余的信息; ibase,obase 用于进制转换,ibase是输入的进制,obase是输出的进制,默认是十进制; scale 小数保留位数,默认保留0位(即整除)。
bc 命令行示例(交互式):
# bc -ilq scale = 0 # 设置默认的小数位为0, 即整数运算 10 + 6 # 加法 16 10 - 6 # 减法 4 10 * 6 # 乘法 60 10 ** 6 # 错误, 不是乘幂 (standard_in) 4: syntax error 10 ^ 6 # 乘幂 1000000 10 % 6 # 取余 4 10 / 6 # 默认 scale=0, 整除, 小数位为0 1 scale = 2 # 设置小数位为2 10 / 6 1.66 scale = 6 # 设置小数位为6 10 / 6 1.666666 scale = 20 # 设置小数位为20 10 / 6 1.66666666666666666666 scale = 50 # 设置小数位为50 10 / 6 1.66666666666666666666666666666666666666666666666666 4 * a(1) # 计算π值,a()是个函数:arctan() 3.14159265358979323846264338327950288419716939937508 ibase = 2 # 设置二进制输入 1010 + 0110 16 # 默认是十进制输出 obase = 2 # 设置十进制输出 1010 + 0110 10000 quit #
bc 命令行示例(非交互式):
# echo "10 + 6" | bc # 加法 16 # echo "10 + 6 * 2 ^ 2" | bc # 四则混合运算 34 # echo "scale=6; 10 / 6" | bc # 除法 1.666666 # echo "s(2/3*a(1))" | bc -l # sina(30°)等于0.5 .49999999999999999998 # echo "s(2/3*a(1))" | bc # sina 三角运算需要到数学库, 要加参数 -l Runtime error (func=(main), adr=10): Function a not defined. # # echo "scale=5; sqrt(16)" | bc # 开方 4.00000 # echo "scale=5; sqrt(15)" | bc -l # 开方, 没用到数学库, 加不加数学库都一样 3.87298 # echo "ibase=16; obase=2; ABC" | bc # 输入十六进制,输出二进制 101010111100
2)脚本语言编程
#!/bin/bash # mimvp.com 2014.10.10 ## 5. bc 高精度小数计算 function mimvp_cal_bc() { m=10 n=6 result=`echo "10 + 6" | bc` # 加法 16 echo ${result} result=`echo "10 - 6" | bc` # 减法 4 echo ${result} result=`echo "10 * 6" | bc` # 乘法 60 echo ${result} result=`echo "10 ^ 6" | bc` # 乘幂 1000000 echo ${result} result=`echo "10 % 6" | bc` # 取余 4 echo ${result} result=`echo "scale=0; 10 / 6" | bc` # 整除 1 echo ${result} result=`echo "scale=2; 10 / 6" | bc` # 小数 1.66 echo ${result} result=`echo "scale=6; sqrt(2)" | bc` # 开方 1.414213 echo ${result} result=`echo "s(2/3*a(1))" | bc -l` # 数学库的三角函数 .49999999999999999998 echo ${result} result=`echo "ibase=16; obase=2; ABC" | bc` # 输入十六进制,输出二进制 101010111100101010111100 echo ${result} } mimvp_cal_bc
6、dc 命令,高精度小数运算
dc 与 bc 非常像,但比bc要复杂,dc是一直压栈操作并计算,较难理解,支持浮点运算,可以交互使用,或者与echo一起配合非交互使用。
dc 命令的参数:
c 清除压栈 d 复制栈顶的值 p 输出栈顶值 q 退出交互模式
dc 命令行示例(交互式):
# dc 10 # 压栈 10 6 # 压栈 6 + # 压栈 + (加号) p # 输出栈顶值 16 10 # 压栈 10 6 # 压栈 6 - # 压栈 - (减号) p # 输出栈顶值 4 10 6 * # 压栈 * (乘号) p 60 10 6^ # 压栈 ^ (乘幂) p 1000000 10 6% # 压栈 % (取余) p 4 10 6 / # 压栈 / (除号) p 1 10 # 累计压栈 6+ 3* p 48 10 # 累计压栈 6+ p # 输出 16 3* p # 输出 48 d # 复制栈顶的值 p 48 c # 清除压栈 p dc: stack empty # 清除压栈后为空栈 q # 退出交互模式 #
说明:是不是看着压栈,就感觉太复杂了,哈哈(涨涨见识,可以不用)
dc 命令行示例(非交互式):
# echo "10 6 + p" | dc 16 # echo "10 6 + 3 * p" | dc 48 # echo "10 6 + 3 * 10 - p" | dc 38
7、Shell awk 循环求和
1. 简单求和
$ cat test.txt 11 22 33 44 55 $ awk '{sum += $1};END{print sum}' test.txt 165
2. 特定列求和
$ cat test.txt aa 11 bb 22 cc 33 aa 44 dd 55 $ awk '/aa/ {sum += $2};END {print sum}' test.txt 55
3. 求和、平均数、最大值、最小值
$ cat test.txt aa 11 bb 22 cc 33 aa 44 dd 55 $ cat test.txt | awk '{sum += $2};END {print sum}' 165 $ cat test.txt | awk '{sum += $2};END {print sum/NR}' 33 $ cat test.txt | awk 'BEGIN {max=0} {if($2>max) max=$2 fi};END {print max}' 55 $ cat test.txt | awk 'BEGIN {min=999999999} {if($2<min) min=$2 fi};END {print min}' 11
awk 高精度小数运算:
运算表达式: awk 'BEGIN{printf "%.6f\n", ( 10 / 3)}'
运算结果: 3.333333
PS:shell 内部算术运算符无法处理浮点数,所以当需要处理浮点数是,要用到外部工具(如awk)
算术应用一:累加计数器
Linux Bash Shell 的四种算术运算方法,并不是每一种都是跨平台的,建议使用 $(()) 和 expr
上述介绍的四种算术运算方法,全部都支持累加计数器
m=$[ m + 1] m=`expr $m + 1` m=$(($m + 1)) let "m=m+1"
完整的示例:
#!/bin/bash # mimvp.com 2014.10.10 ## 应用一: 累计计数器 function mimvp_loop() { count=0 count=`expr ${count} + 1` echo ${count} count=$(( count + 1 )) echo ${count} count=$[ count + 1 ] echo ${count} let "count = count + 1" echo ${count} } mimvp_loop
算术应用二:统计 CPU、内存、磁盘
Linux Bash Shell 统计系统的 CPU、内存、磁盘等信息,是非常实用的,结合邮件可以发送系统报警通知
#!/bin/bash # mimvp.com 2014.10.10 ## 应用二: 统计 CPU、内存、磁盘 function mimvp_stat() { log='mimvp_stat_disk.log' KB=1024 MB=`expr 1024 \* 1024` GB=`expr 1024 \* 1024 \* 1024` TB=`expr 1024 \* 1024 \* 1024 \* 1024` dtime=$(date "+%Y-%m-%d__%H:%M:%S") echo "========= $dtime =========" df -m echo "" disk_total_MB=`df -hm | grep "/dev/vda1" | awk '{print $2}'` disk_used_MB=`df -hm | grep "/dev/vda1" | awk '{print $3}'` disk_used_GB=`expr $disk_used_MB / 1024` disk_used_TB=`expr $disk_used_GB / 1024` disk_used_GB_2=`echo "scale=2; $disk_used_MB / 1024" | bc` disk_used_TB_2=`echo "scale=2; $disk_used_GB / 1024" | bc` disk_used_GB_3=`awk 'BEGIN{printf "%.2f", '$disk_used_MB' / 1024}'` disk_used_TB_3=`awk 'BEGIN{printf "%.2f", '$disk_used_GB' / 1024}'` disk_used_ratio=`awk 'BEGIN {printf "%.2f%", '$disk_used_MB' / '$disk_total_MB' * 100}'` echo -e "MB : $MB" echo -e "GB : $GB" echo -e "disk_total_MB : $disk_total_MB" echo -e "disk_used_MB : $disk_used_MB" echo -e "disk_used_ratio : $disk_used_ratio" echo -e "disk_used_GB : $disk_used_GB" echo -e "disk_used_TB : $disk_used_TB" echo -e "disk_used_GB_2 : $disk_used_GB_2" echo -e "disk_used_TB_2 : $disk_used_TB_2" echo -e "disk_used_GB_3 : $disk_used_GB_3" echo -e "disk_used_TB_3 : $disk_used_TB_3" } mimvp_stat
总结
本文总结了 Linux Shell 常见的算术运算,包含了 整数、小数精度、字符串运算等
expr、let、$(())、$[] 等只支持整数运算,但对于浮点运算就无能为力了
bc、dc、awk 支持浮点计算
expr 还支持字符串操作
您有更好的方法,欢迎留言补充,谢谢。
最后,附上完整的 shell 代码,方便爱好者研究、调试
#!/bin/bash # mimvp.com 2014.10.10 ## 1. expr , 不支持乘幂、异或 function mimvp_cal_expr() { m=10 n=6 result=`expr $m + $n` # 加法 16 echo ${result} result=`expr $m - $n` # 减法 4 echo ${result} result=`expr $m \* $n` # 乘法 60 echo ${result} result=`expr $m / $n` # 除法 1 echo ${result} result=`expr $m % $n` # 取余 4 echo ${result} } ## 1. expr str 字符串操作 function mimvp_cal_expr_str() { str="1234567890" # 1.1 length 获取字符串长度 str_length=`expr length ${str}` # expr str_length=`echo ${str} | awk '{print length}'` # awk str_length=${#str} # ${} echo "str_length: ${str_length}" # 10 # 1.2 index 获取字串出现的下标 str_index=`expr index ${str} "567"` # 下标从1算起, 匹配子串中任意字符最先出现的位置, 返回5 str_index=`expr index ${str} "765"` # 下标从1算起, 匹配子串中任意字符最先出现的位置, 返回5 str_index=`expr index ${str} "768"` # 下标从1算起, 匹配子串中任意字符最先出现的位置, 返回6 str_index=`expr index ${str} "abc"` # 未匹配, 返回0 echo "str_index: ${str_index}" # # 1.3 substr 截取获得子串 str_substr=`expr substr ${str} 5 3` # expr 下标从1算起, 从第5位截取长度为3, 返回567 str_substr=`echo ${str} | awk '{print substr($0,5,3)}'` # awk 下标从1算起, 从第5位截取长度为3, 返回567 str_substr=${str:5:3} # ${} 下标从0算起, 从第5位截取长度为3, 返回678 echo "str_substr: ${str_substr}" # # 1.4 match 匹配获取字串的长度, 匹配不到则返回0 str_match=`expr match ${str} 123` # 从第一个字母开始匹配, 返回匹配到的字串长度, 返回3 str_match=`expr match ${str} .*8` # 从第一个字母开始匹配, 正则表达式匹配到8结束, 返回8 str_match=`expr match ${str} 456` # 从第一个字母开始匹配, 子串456不是开始字母, 匹配失败, 返回0 echo "str_match: ${str_match}" # } ## 2. $(()) , 用法完全等同于$[] function mimvp_cal_dollar() { m=10 n=6 result=$(( $m + $n )) # 加法 16 result=$(( m + n )) # 加法 16 echo ${result} result=$(( m - n )) # 减法 4 echo ${result} result=$(( m * n )) # 乘法 60 echo ${result} result=$(( m ** n )) # 乘幂 1000000 echo ${result} result=$(( m ^ n )) # 异或 12 (二进制 1010^0110 1100 echo ${result} result=$(( m / n )) # 除法 1 echo ${result} result=$(( m % n )) # 取余 4 echo ${result} } ## 3. $[] , 用法完全等同于$(()) function mimvp_cal_square() { m=10 n=6 result=$[ $m + $n ] # 加法 16 result=$[ m + n ] # 加法 16 echo ${result} result=$[ m - n ] # 减法 4 echo ${result} result=$[ m * n ] # 乘法 60 echo ${result} result=$[ m ** n ] # 乘幂 1000000 echo ${result} result=$[ m ^ n ] # 异或 12 (二进制 1010^0110 1100 echo ${result} result=$[ m / n ] # 除法 1 echo ${result} result=$[ m % n ] # 取余 4 echo ${result} } ## 4. let function mimvp_cal_let() { m=10 n=6 let "result = $m + $n" # 加法 16 let "result = m + n" # 加法 16 echo ${result} let "result = m - n" # 减法 4 echo ${result} let "result = m * n" # 乘法 60 echo ${result} let "result = m ** n" # 乘幂 1000000 echo ${result} let "result = m ^ n" # 异或 12 (二进制 1010^0110 1100 echo ${result} let "result = m / n" # 除法 1 echo ${result} let " result = m % n " # 取余 4 echo ${result} } ## 5. bc 高精度小数计算 function mimvp_cal_bc() { m=10 n=6 result=`echo "10 + 6" | bc` # 加法 16 echo ${result} result=`echo "10 - 6" | bc` # 减法 4 echo ${result} result=`echo "10 * 6" | bc` # 乘法 60 echo ${result} result=`echo "10 ^ 6" | bc` # 乘幂 1000000 echo ${result} result=`echo "10 % 6" | bc` # 取余 4 echo ${result} result=`echo "scale=0; 10 / 6" | bc` # 整除 1 echo ${result} result=`echo "scale=2; 10 / 6" | bc` # 小数 1.66 echo ${result} result=`echo "scale=6; sqrt(2)" | bc` # 开方 1.414213 echo ${result} result=`echo "s(2/3*a(1))" | bc -l` # 数学库的三角函数 .49999999999999999998 echo ${result} result=`echo "ibase=16; obase=2; ABC" | bc` # 输入十六进制,输出二进制 101010111100101010111100 echo ${result} } ## 应用一: 累计计数器 function mimvp_loop() { count=0 count=`expr ${count} + 1` echo ${count} count=$(( count + 1 )) echo ${count} count=$[ count + 1 ] echo ${count} let "count = count + 1" echo ${count} } ## 应用二: 统计 CPU、内存、磁盘 function mimvp_stat() { log='mimvp_stat_disk.log' KB=1024 MB=`expr 1024 \* 1024` GB=`expr 1024 \* 1024 \* 1024` TB=`expr 1024 \* 1024 \* 1024 \* 1024` dtime=$(date "+%Y-%m-%d__%H:%M:%S") echo "========= $dtime =========" df -m echo "" disk_total_MB=`df -hm | grep "/dev/vda1" | awk '{print $2}'` disk_used_MB=`df -hm | grep "/dev/vda1" | awk '{print $3}'` disk_used_GB=`expr $disk_used_MB / 1024` disk_used_TB=`expr $disk_used_GB / 1024` disk_used_GB_2=`echo "scale=2; $disk_used_MB / 1024" | bc` disk_used_TB_2=`echo "scale=2; $disk_used_GB / 1024" | bc` disk_used_GB_3=`awk 'BEGIN{printf "%.2f", '$disk_used_MB' / 1024}'` disk_used_TB_3=`awk 'BEGIN{printf "%.2f", '$disk_used_GB' / 1024}'` disk_used_ratio=`awk 'BEGIN {printf "%.2f%", '$disk_used_MB' / '$disk_total_MB' * 100}'` echo -e "MB : $MB" echo -e "GB : $GB" echo -e "disk_total_MB : $disk_total_MB" echo -e "disk_used_MB : $disk_used_MB" echo -e "disk_used_ratio : $disk_used_ratio" echo -e "disk_used_GB : $disk_used_GB" echo -e "disk_used_TB : $disk_used_TB" echo -e "disk_used_GB_2 : $disk_used_GB_2" echo -e "disk_used_TB_2 : $disk_used_TB_2" echo -e "disk_used_GB_3 : $disk_used_GB_3" echo -e "disk_used_TB_3 : $disk_used_TB_3" } mimvp_cal_expr #mimvp_cal_expr_str #mimvp_cal_dollar #mimvp_cal_square #mimvp_cal_let #mimvp_cal_bc #mimvp_loop #mimvp_stat
参考推荐:
Centos7 配置 sendmail、postfix 端口号25、465
版权所有: 本文系米扑博客原创、转载、摘录,或修订后发表,最后更新于 2019-01-30 11:06:10
侵权处理: 本个人博客,不盈利,若侵犯了您的作品权,请联系博主删除,莫恶意,索钱财,感谢!
转载注明: Linux Shell 算术运算 (米扑博客)