天天看點

Linux-shell-算術運算{expr、bc、dc、(( ))和[ ]}

在Linux下做算術運算時你是如何進行的呢?是不是還在用expr呢?你會說我還會bc還有其它的呢!

閑話不多扯,幹正事!

expr

expr在使用中要注意一些書寫,如表達式中量和運算符号之間的空格及一些運算符号需要轉義,還有一點需要記住,expr隻适用于整數之間的運算!

表達式

expr的help文檔中關于表達式部分如下:

ARG1 | ARG2       若ARG1 的值不為0 或者為空,則傳回ARG1,否則傳回ARG2
 
  ARG1 & ARG2       若兩邊的值都不為0 或為空,則傳回ARG1,否則傳回 0
 
  ARG1 < ARG2       ARG1 小于ARG2
  ARG1 <= ARG2      ARG1 小于或等于ARG2
  ARG1 = ARG2       ARG1 等于ARG2
  ARG1 != ARG2      ARG1 不等于ARG2
  ARG1 >= ARG2      ARG1 大于或等于ARG2
  ARG1 > ARG2       ARG1 大于ARG2
 
  ARG1 + ARG2       計算 ARG1 與ARG2 相加之和
  ARG1 - ARG2       計算 ARG1 與ARG2 相減之差
 
  ARG1 * ARG2       計算 ARG1 與ARG2 相乘之積
  ARG1 / ARG2       計算 ARG1 與ARG2 相除之商
  ARG1 % ARG2       計算 ARG1 與ARG2 相除之餘數      

這一部分相信大家用的最多,也對這些比較了解了,下面我們用一個表達式來說明:

$expr 9 + 8 - 7 \* 6 / 5 + \( 4 - 3 \) \* 2
11      

通過結果相信你已知道expr的計算規律,它與我們日常所了解的數學表達式一樣,括号的優先級最高,然後是“*”、“/”,而且每個數或符号都需要用空格分隔,結果也是整數。

字元串

expr還可以對字元串進行操作:

match 字元串 表達式等于"字元串 :表達式"
  substr 字元串 偏移量 長度替換字元串的子串,偏移的數值從 1 起計
  index 字元串 字元在字元串中發現字元的地方建立下标,或者标0
  length 字元串字元串的長度      

1)match

expr中的expr match $string substring指令在string字元串中比對substring字元串(substring字元串可以是正規表達式),然後傳回比對到的substring字元串的長度,若找不到則傳回0。

下面我們來個執行個體:

┌[2013-08-24/7.18  15:00:01]
├[14+1][~]
└[snowsolf@Ubuntu-LTS-1 ╰_╯]$str="123 456 789"
┌[2013-08-24/7.18  15:00:30]
├[14+1][~]
└[snowsolf@Ubuntu-LTS-1 ╰_╯]$expr match "$str" .*5
6      

.*5比對了6個字元。

2)substr

在shell中可以用{string:position}和{string:position:length}進行對string字元串中字元的抽取。第一種是從position位置開始抽取直到字元串結束,第二種是從position位置開始抽取長度為length的子串。而用expr中的expr substr $string $position $length同樣能實作上述功能。

執行個體:

┌[2013-08-24/7.18  15:19:17]
├[14+1][~]
└[snowsolf@Ubuntu-LTS-1 ╰_╯]$str="123 456 789"
┌[2013-08-24/7.18  15:19:31]
├[14+1][~]
└[snowsolf@Ubuntu-LTS-1 ╰_╯]$echo ${str:5}
56 789
┌[2013-08-24/7.18  15:19:59]
├[14+1][~]
└[snowsolf@Ubuntu-LTS-1 ╰_╯]$echo ${str:5:3}
56
┌[2013-08-24/7.18  15:20:07]
├[14+1][~]
└[snowsolf@Ubuntu-LTS-1 ╰_╯]$expr substr "$str" 5 3
456      

從中可以看出{string:position}和{string:position:length}從0開始計數,而expr substr $string $position $length從1開始。

3)index

expr中的expr index $string substring索引指令功能在字元串$string上找出substring中字元第一次出現的位置,若找不到則expr index傳回0。注意它比對的是字元而非字元串。

┌[2013-08-24/7.18  15:35:19]
├[14+1][~]
└[snowsolf@Ubuntu-LTS-1 ╰_╯]$str="123 456 789"
┌[2013-08-24/7.18  15:37:02]
├[14+1][~]
└[snowsolf@Ubuntu-LTS-1 ╰_╯]$expr index "$str" b
0
┌[2013-08-24/7.18  15:37:08]
├[14+1][~]
└[snowsolf@Ubuntu-LTS-1 ╰_╯]$expr index "$str" 9
11      

4)length

計算字元串的長度。我們可以用awk中的length(s)進行計算。我們也可以用echo中的echo ${#string}進行計算,當然也可以expr中的expr length $string 求出字元串的長度。

┌[2013-08-24/7.18  15:39:39]
├[14+1][~]
└[snowsolf@Ubuntu-LTS-1 ╰_╯]$str="123 456 789"
┌[2013-08-24/7.18  15:39:52]
├[14+1][~]
└[snowsolf@Ubuntu-LTS-1 ╰_╯]$echo ${#str}
11
┌[2013-08-24/7.18  15:39:57]
├[14+1][~]
└[snowsolf@Ubuntu-LTS-1 ╰_╯]$expr length "$str"
11      

bc

重點來了!

bc是一種任意精度的計算語言,注意是一種語言,它提供了一些文法結構,比如條件判斷、循環等,可以說是很強大的,但是我在實際中還沒有找到需要這個用途的場合 。另外一個用途就是用來進行進制轉換。

上面我們介紹的expr之支援整數運算,但對于浮點運算就無能為力了,而且expr不能進行指數運算,而都有bc這些都不再話下。

參數

我們先來了解幾個有用的參數:

-i 強制互動模式;

-l 使用bc的内置庫,bc裡有一些數學庫,對三角計算等非常實用;

-q 進入bc互動模式時不再輸出版本等多餘的資訊。      

特殊變量

ibase,obase 用于進制轉換,ibase是輸入的進制,obase是輸出的進制,預設是十進制;

scale 小數保留位數,預設保留0位。

互動模式

在shell指令行直接輸入bc及能進入bc語言的互動模式。

$bc -l -q
4/3                           /*未指定精度預設保留整數*/
1
scale=5                       /*指定精度為5*/
4/3
1.33333
ibase=2                       /*指定進制轉換的輸入機制為二進制,輸出預設為是十進制*/
1010
10
4^2                           /*指數運算,注:指數不能為浮點數*/
16
4*a(1)                        /*計算π值,a()是個函數:arctan(),好吧,老師教的都被狗吃了,π值是等于四倍的arctan(1)麼?*/
3.14159265358979323844
quit                          /*退出*/      

非互動模式

bc也可以進行非互動式的運算,方法是與echo一起使用。

┌[2013-08-24/7.18  18:42:27]
├[14+1][~]
└[snowsolf@Ubuntu-LTS-1 ╰_╯]$echo "scale=5;9+8-7*6/5^2"|bc          /*優先級^ > *、/ > +、- */
15.32000
┌[2013-08-24/7.18  18:45:35]
├[14+1][~]
└[snowsolf@Ubuntu-LTS-1 ╰_╯]$echo "s(2/3*a(1))"|bc -l               /*還記得sina(30°)等于0.5麼?皇上! ^_^*/
.49999999999999999998
┌[2013-08-24/7.18  18:49:13]
├[14+1][~]
└[snowsolf@Ubuntu-LTS-1 ╰_╯]$echo "scale=5;sqrt(15)"|bc             /*開方*/
3.87298
┌[2013-08-24/7.18  18:49:18]
├[14+1][~]
└[snowsolf@Ubuntu-LTS-1 ╰_╯]$echo "ibase=16;obase=2;ABC"|bc
101010111100      

更多參考man文檔!

dc

可能你曾經知道有此指令,也可能你還不知道。dc相比與bc要複雜,但是簡單操作還是比較簡單。簡單的說dc是一直壓棧操作,和bc一樣,它也可以互動使用,或者與echo一起配合使用。

它也支援浮點運算。

但是現在我還沒有想到這種壓棧式算術運算有什麼優點。

┌[2013-09-16/8.12  20:33:53]
├[7+10][~/shell]
└[snowsolf@Ubuntu-LTS-1 ╰_╯]$dc
2
3-
p      /*輸出(2 - 3)*/
-1
4
*
p      /*輸出(-1 * 4)*/
-4
2
/
p      /*輸出(-4 / 2)*/
-2
3.4
+
p      /*輸出(-2 + 3.4)*/
1.4
4
d      /*複制棧頂值*/
*
p      /*輸出(4 * 4)*/
16
q      /*退出*/      

還有其他指令如:

c           清除壓棧

d           複制棧頂的值

p           輸出棧頂值

q           退出互動模式      

還有其它可以參考對應man文檔。

一個算式讓你就看的差不多了。

┌[2013-09-16/8.12  20:47:43]
├[7+10][~/shell]
└[snowsolf@Ubuntu-LTS-1 ╰_╯]$echo "4 3 * 2 + 1 -p"|dc
13      

算式是:(4 * 3 + 2 - 1)。

是不是很簡單!

(( )) & [ ]

這兩個在shell中比較常見,這兩個和expr指令有些類似,也是用于整數計算。

他們支援的運算符号有如下:

|    位或
+ ||   若前後兩者都不為0,則傳回1,否則傳回0
 &  位與
+ &&  若前者為0,不再對後者進行處理,否則對後者處理,後者不為0時傳回1
 < 
 <=
 ==
 !=
 >=
 > 
 + 
 - 
 * 
 / 
 %       

帶+号的兩個運算符其實是shell支援的運算符。

這兩個對與expr的優點是:運算符号全部不需要轉義。

我們一味的在shell中用那些别人沒用過的指令來做同一件事,但不要忘了(( ))和[ ]是shell中常見的,而且非常實用,但并非是你常用的!

┌[2013-09-16/8.12  20:47:51]
├[7+10][~/shell]
└[snowsolf@Ubuntu-LTS-1 ╰_╯]$echo $(( 2 + 5 ))
7
┌[2013-09-16/8.12  21:11:14]
├[7+10][~/shell]
└[snowsolf@Ubuntu-LTS-1 ╰_╯]$echo $(( 2 * 5 ))
10
┌[2013-09-16/8.12  21:11:19]
├[7+10][~/shell]
└[snowsolf@Ubuntu-LTS-1 ╰_╯]$echo $(( 2 - 5 ))
-3
┌[2013-09-16/8.12  21:11:23]
├[7+10][~/shell]
└[snowsolf@Ubuntu-LTS-1 ╰_╯]$echo $(( 2 % 5 ))
2
┌[2013-09-16/8.12  21:11:29]
├[7+10][~/shell]
└[snowsolf@Ubuntu-LTS-1 ╰_╯]$echo $[ 2 % 5 ]
2
┌[2013-09-16/8.12  21:11:45]
├[7+10][~/shell]
└[snowsolf@Ubuntu-LTS-1 ╰_╯]$echo $[ 2 - 5 ]
-3
┌[2013-09-16/8.12  21:11:50]
├[7+10][~/shell]
└[snowsolf@Ubuntu-LTS-1 ╰_╯]$echo $[ 2 * 5 ]
10
┌[2013-09-16/8.12  21:11:55]
├[7+10][~/shell]
└[snowsolf@Ubuntu-LTS-1 ╰_╯]$echo $[ 2 + 5 ]
7      

獨行者如風!

上一篇: 實驗四