對于在Shell中進行數字的計算,其實方法有很多,但是常用的方法都有其弱點:
?
1、bc
????bc應該是最常用的Linux中計算器了,簡單方便,支持浮點。
[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,情何以堪!
[wangdong@centos715-node1?~]$?echo?"scale=2;1/2"?|bc .50 [wangdong@centos715-node1?~]$?echo?"scale=4;17/20"?|bc???? .8500
????而且…… 像一些第三方基于Linux底層的產品,為了系統本身的穩定和輕便,默認是不帶bc的,例如……F5
?
2、expr
????不支持浮點計算,即不支持小數,所以也常被用來判斷變量內容或者結果是不是非0整數(expr 0的echo $?不是0)。
[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
3、$(())
????不支持浮點計算。
[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")
?
4、let
????不僅不支持浮點計算,而且還只能賦值,不能直接輸出。
[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