Shell數值運算方法(3種)

2020-07-16 10:04:34
Shell 程式設計和其他語言還是有很多不一樣的地方的,其中筆者最不習慣的是:在 Shell 中所有的變數預設都是"字串型"。也就是說,如果不手工指定變數的型別,那麼所有的數值都是不能進行運算的。比如:

[[email protected] sh]# aa=11
[[email protected] sh]# bb=22
#給變數aa和bb賦值
[[email protected] sh]# cc=$aa+$bb
#我想讓cc的值是aa和bb的和
[[email protected] sh]# echo $cc
11+22
#但是cc的值卻是"11+22"這個字串,並沒有進行數值運算

如果需要進行數值運算,則可以採用以下三種方法中的任意一種。

使用declare宣告變數型別

既然所有變數的預設型別是字串型,那麼只要把變數宣告為整數型不就可以參與運算了嗎?使用 declare 命令就可以宣告變數的型別。

declare 命令格式如下:

[[email protected] ~]# declare [+/-] [選項] 變數名

選項:
  • -:給變數設定型別屬性;
  • +:取消變數的型別屬性;
  • -a:將變數宣告為陣列型;
  • -i:將變數宣告為整數型(integer);
  • -r:將變數宣告為唯讀變數。注意,一旦設定為唯讀變數,既不能修改變數的值,也不能刪除變數,甚至不能通過 +r 取消唯讀屬性;
  • -x:將變數宣告為環境變數;
  • -p:顯示指定變數的被宣告的型別;

【例 1】數值運算

只要把變數宣告為整數型就可以參與運算了嗎?試試吧:

[[email protected] ~]# aa=11
[[email protected] ~]# bb=22
#給變數aa和bb賦值
[[email protected] ~]# declare -i cc=$aa+$bb #宣告變數cc的型別是整數型,它的值是aa和bb的和
[[email protected] ~]# echo $cc
33
#這下終於可以相加了

這樣運算好麻煩!沒有辦法,Shell 在數值運算方面確實是比較麻煩的,習慣就好了。

【例 2】陣列變數型別

陣列是什麼呢?所謂陣列,就是相同資料型別的元素按一定順序排列的集合,也就是把有限個型別相同的變數用一個名字命名,然後用編號區分它們的變數的集合,我們把這個名字稱為陣列名,把編號稱為下標。組成陣列的各個變數被稱為陣列的分量,又稱陣列的元素,下標變數。

一看定義就一頭霧水,更加不明白陣列是什麼了。那麼換一種說法,變數和陣列都是用來儲存資料的,只是變數只能被賦予一個資料值,一旦重複賦值,後一個值就會覆蓋前一個值;而陣列可以被賦予一組相同型別的資料值。

大家可以把變數想象成一間小辦公室,這間辦公室裡只能容納一個人辦公,辦公室名就是變數名;而陣列是一間大辦公室,可以容納很多人同時辦公,在這間大辦公室裡辦公的每個人是通過不同的座位號來區分的,這個座位號就是陣列的下標,而大辦公室的名字就是陣列名。

還是舉個例子吧:

[[email protected] ~]# name[0]="zhang san"
#陣列中第一個變數是張三
[[email protected] ~]# name[1]="li ming"
#陣列中第二個變數是李明
[[email protected] ~]# name[2]="gao luo feng"
#陣列中第三個變數是高洛峰
[[email protected] ~]# echo ${name}
zhang san
#輸出陣列的內容。如果只寫陣列名,那麼只會輸出第一個下標變數
[[email protected] ~]# echo ${name[*]}
zhang san li ming gao luo feng
#輸出陣列所有的內容

注意,陣列的下標是從 0 開始的,在呼叫陣列的元素時,需要使用"${陣列[下標]}"方式來讀取。

不過,在剛剛的例子中,我們並沒有把 name 變數宣告為陣列型。其實只要我們在定義變數時採用了"變數名 [下標]"的格式,這個變數就會被系統認為是陣列型了,不用強制宣告。

【例 3】環境變數

其實也可以使用 declare 命令把變數宣告為環境變數,它和 export 命令的作用是一樣的。命令如下:

[[email protected] ~]# declare -x test=123
#把變數test宣告為環境變數

【例 4】唯讀屬性

一旦給變數設定了唯讀屬性,那麼這個變數既不能修改變數的值,也不能刪除變數,甚至不能使用"+r"選項取消唯讀屬性。命令如下:

[[email protected] ~]# declare -r test
#給test變數賦予唯讀屬性
[[email protected] ~]#test=456
-bash:test: readonly variable
#test變數的值就不能修改了
[[email protected] ~]# declare +r test
-bash:declare:test:readonly variable
#也不能取消唯讀屬性
[[email protected] ~]# unset test
-bash: unset: test: cannot unset: readonly variable
#也不能刪除變數

不過,還好這個變數只是命令列宣告的,所以只要重新登陸或重新啟動,這個變數就會消失了。

【例 5】查詢變數屬性和取消變數屬性

變數屬性的查詢使用"-p"選項,變數屬性的取消使用"+"選項。命令如下:

[[email protected] ~]# declare -p cc
declare -i cc="33"
#cc變數是int型
[[email protected] ~]# declare -p name
declare -a name='([0]="zhang san" [1]="li ming" [2]="gao luo feng")'
#name變數是陣列型
[[email protected] ~]# declare -p test
declare -rx test="123"
#test變數是環境變數和唯讀變數
[[email protected] ~]# declare +x test
#取消test變數的環境變數屬性
[[email protected] ~]# declare -p test
declare-rtest="123"
#注意:唯讀變數屬性是不能被取消的

使用expr或let數值運算工具

進行數值運算的第二種方法是使用 exp 命令,這個命令就沒有 declare 命令那麼複雜了。命令如下:

[[email protected] ~]# aa=11
[[email protected] ~]# bb=22
#給變數aa和bb賦值
[[email protected] ~]# dd=$(expr $aa + $bb)
#dd的值是aa和bb的和。注意"+"號左右兩側必須有空格
[[email protected] ~]# echo $dd
33

在使用 expr 命令進行運算時,要注意"+"號左右兩側必須有空格,否則運算不執行。

至於 let 命令,和 expr 命令基本類似,都是 Linux 中的運算命令。命令如下:

[[email protected] ~]# aa=11
[[email protected] ~]# bb=22
#給變數aa和bb賦值
[[email protected] ~]# let ee=$aa+$bb
[[email protected] ~]# echo $ee
33
#變數ee的值是aa和bb的和
[[email protected] ~]# n=20
#定義變數n
[[email protected] ~]# let n+=1
#變數n的值等於變數本身再加1
[[email protected] ~]# echo $n
21

expr 和 let 命令大家可以按照習慣使用,不過 let 命令對格式的要求要比 exp 命令格式的要求寬鬆,所以推薦使用 let 命令進行數值運算。

使用"$((運算式))"或"$[運算式]"方式運算

其實這是一種方式,"$(())"和"$[]"這兩種括號按照個人習慣使用即可。命令如下:

[[email protected] ~]# aa=11
[[email protected] ~]# bb=22
[[email protected] ~]# ff=$(( $aa+$bb))
[[email protected] ~]# echo $ff
33
#變數ff的值是aa和bb的和
[[email protected] ~]# gg=$[ $aa+$bb ]
[[email protected] ~]# echo $gg
33
#變數gg的值是aa和bb的和

這三種數值運算方式,大家可以按照自己的習慣來選擇使用。不過我們推薦使用"$((運算式))",這種方式更加簡單,也更加常用。