对于在Shell中进行数字的计算,其实方法有不少,可是经常使用的方法都有其弱点:node
一、bcshell
bc应该是最经常使用的Linux中计算器了,简单方便,支持浮点。
express
[wangdong@centos715-node1 ~]$ echo 1+2 |bc 3 [wangdong@centos715-node1 ~]$ echo 5.5*3.3 |bc 18.1 [wangdong@centos715-node1 ~]$ echo 5/3 |bc 1 [wangdong@centos715-node1 ~]$ echo "scale=2;5/3" |bc 1.66
看似在简单计算时候完美的bc,其实也有一个让我抓狂的地方,固然有可能有办法能够解决,只是我不知道而已,那就是…… 在出现整数部分为0的时候,这个0是不显示出来的,例如0.5只会显示为.5,情何以堪!centos
[wangdong@centos715-node1 ~]$ echo "scale=2;1/2" |bc .50 [wangdong@centos715-node1 ~]$ echo "scale=4;17/20" |bc .8500
并且…… 像一些第三方基于Linux底层的产品,为了系统自己的稳定和轻便,默认是不带bc的,例如……F5
bash
二、expride
不支持浮点计算,即不支持小数,因此也常被用来判断变量内容或者结果是否是非0整数(expr 0的echo $?不是0)。centos7
[wangdong@centos715-node1 ~]$ expr 3 + 5 8 [wangdong@centos715-node1 ~]$ expr 10 / 2 5 [wangdong@centos715-node1 ~]$ expr 10 / 3 3 [wangdong@centos715-node1 ~]$ expr 7 / 2 3 [wangdong@centos715-node1 ~]$ expr 0 0 [wangdong@centos715-node1 ~]$ echo $? 1
三、$(())spa
不支持浮点计算。
字符串
[wangdong@centos715-node1 ~]$ echo $((8+3)) 11 [wangdong@centos715-node1 ~]$ echo $((10/2)) 5 [wangdong@centos715-node1 ~]$ echo $((10/3)) 3 [wangdong@centos715-node1 ~]$ echo $((1.5*3)) -bash: 1.5*3: 语法错误: 无效的算术运算符 (错误符号是 ".5*3")
四、let
cmd
不只不支持浮点计算,并且还只能赋值,不能直接输出。
[wangdong@centos715-node1 ~]$ let a=1+2 [wangdong@centos715-node1 ~]$ echo $a 3 [wangdong@centos715-node1 ~]$ let b=10/5 [wangdong@centos715-node1 ~]$ echo $b 2 [wangdong@centos715-node1 ~]$ let c=1.5*3 -bash: let: c=1.5*3: 语法错误: 无效的算术运算符 (错误符号是 ".5*3") [wangdong@centos715-node1 ~]$ echo $c [wangdong@centos715-node1 ~]$
上面的几种方式,是我以前经常使用的方式,可是如今我在shell脚本中有一个需求,在计算数字时,会出现浮点计算,也会出现0-1之间的小数,前面的几个方式恐怕都没法知足。
这里,我使用的是awk计算:
[wangdong@centos715-node1 ~]$ echo | awk '{print 17/20}' 0.85 [wangdong@centos715-node1 ~]$ echo | awk '{print 1.5*3}' 4.5
看上去还能够,那么进一步,我须要带变量:
[wangdong@centos715-node1 ~]$ A=5 [wangdong@centos715-node1 ~]$ B=16 [wangdong@centos715-node1 ~]$ C=29 [wangdong@centos715-node1 ~]$ echo | awk '{print $A/$B}' awk: cmd. line:1: (FILENAME=- FNR=1) fatal: division by zero attempted [wangdong@centos715-node1 ~]$ echo | awk "{print $A/$B}" 0.3125 [wangdong@centos715-node1 ~]$ echo | awk "{print $C*$A}" 145 [wangdong@centos715-node1 ~]$ echo | awk "{print $C*$A/$B}" 9.0625
看上去也还能够,只是注意awk后的单引号须要变为双引号。
再进一步,上面最后一次的计算,小数点后面出现了4位,我但愿只保留两位,否则看着太乱。可是没有找到这里能够保留小数位的参数和方法,因而我尝试一下将print换为printf:
[wangdong@centos715-node1 ~]$ echo | awk '{print 10/3}' 3.33333 [wangdong@centos715-node1 ~]$ echo | awk '{printf ("%.2f\n",10/3)}' 3.33
将print换成printf,就能够有方法进行小数位的限制了,看似不错,可是……
[wangdong@centos715-node1 ~]$ A=5 [wangdong@centos715-node1 ~]$ B=16 [wangdong@centos715-node1 ~]$ C=29 [wangdong@centos715-node1 ~]$ echo | awk '{printf ("%.2f\n",$A/$B)}' awk: cmd. line:1: (FILENAME=- FNR=1) fatal: division by zero attempted [wangdong@centos715-node1 ~]$ echo | awk "{printf ("%.2f\n",$A/$B)}" awk: cmd. line:1: {printf (%.2fn,5/16)} awk: cmd. line:1: ^ syntax error [wangdong@centos715-node1 ~]$ echo | awk "{printf ('%.2f\n',$A/$B)}" awk: cmd. line:1: {printf ('%.2f\n',5/16)} awk: cmd. line:1: ^ invalid char ''' in expression awk: cmd. line:1: {printf ('%.2f\n',5/16)} awk: cmd. line:1: ^ syntax error
使用变量参与计算的话,会发现一直在报错,这种状况,建议先在前面的echo中将须要使用的变量输出出来,再进行调用。
[wangdong@centos715-node1 ~]$ A=5 [wangdong@centos715-node1 ~]$ B=16 [wangdong@centos715-node1 ~]$ C=29 [wangdong@centos715-node1 ~]$ D=6 [wangdong@centos715-node1 ~]$ echo "$A $B $C $D" | awk '{printf ("%.2f\n",$1*$2/$3-$4)}' -3.24 [wangdong@centos715-node1 ~]$ echo "$A $B $C $D" | awk '{printf ("%.2f\n",$1/$4)}' 0.83 [wangdong@centos715-node1 ~]$ echo "$A $B $C $D" | awk '{printf ("%.3f\n",$1/$4)}' 0.833
注意,使用printf的时候,awk后面必须是单引号,双引号会报错。虽然这种方法麻烦一些,可是起码能够实现个人需求,若是有朋友知道bc计算的结果为0-1之间的小数时,怎么让他显示出来前面的0. ,欢迎留言,不喜勿喷。
补充,有的时候在计算数字后,会发现你的结果已经不是正常的一串数字了,而是在其中穿插了字母e或者E,这是由于数字过大,系统采用了相似于科学计数法的表达方式(正确叫法不肯定,勿喷),可是若是直接使用这一串内容再去计算的话,会报错,系统会认为这是字符串而非数字,这种状况也可使用awk进行转变,其实准确的说是printf的功能。
[wangdong@centos715-node1 uncomp]$ echo "6.8923e+08/100" |bc (standard_in) 1: syntax error [wangdong@centos715-node1 uncomp]$ echo "6.8923e+08" | awk '{printf ("%.0f\n",$1)}' 689230000