基於上一篇的基礎語法,我來寫寫一些更進一層的語法規則,也是咱們平時若是要進行Shell編程的話,常用的點,其中包括這幾個話題:數組、雙小括號的算術運算、函數、退出碼,篇幅相較上一篇來講不長。程序員
數組,在shell中操控起來比較「所見即所得」的感受,沒有一堆要記住的api接口,頂多就是三四個語法上的輔助。對於數組,基於Bash4.0以後分爲:基本數據和關聯數組。關聯數組有點像咱們Java中的Map,不過功能就簡單多了。正則表達式
直接上代碼:shell
#!/bin/bash var=test4 # 定義一個簡單的基本數組,能夠發現有多種賦值的方式 array_var=(test1 'test2' "test3" "$var") # 這種只能輸出數組的第一個位置的數據 echo $array_var # 注意這種只能輸出test1[1],後面的索引定位並無生效 echo $array_var[1] # 這種,使用大括號將數組和索引括起來的語法,才能使索引生效,取到數組具體位置上面的值 echo ${array_var[1]} # 這兩種均可以將數組打印出來 echo ${array_var[*]} echo ${array_var[@]} # 這種能夠打印數組的個數 echo ${#array_var[*]} # 刪除某個索引位置上面的值 unset array_var[1] <<COMMENT 輸出結果: test1 test1[1] test2 test1 test2 test3 test4 test1 test2 test3 test4 4 COMMENT
好幾種定義數組並初始化的方式,下面來看:編程
#!/bin/bash # 第一種 array_var=( var1 var2 var3 ) # 第二種 array_var=(var1 var2 var3) # 第三種 array_var[0]=var1 array_var[1]=var2 array_var[2]=var2 # 第四種 array_var=([0]=var1 [1]=var2 [3]=var3) # 第五種 str="var1 var2 var3" array_var=($str)
注意最後一種,是用來字符串轉數組的主要方式,用的不少flask
兩種:api
#!/bin/bash array=(var1 var2) # 第一種 len=${#array[@]} array[$len]=var3 # 第二種 array=(${array[@]} var3)
好幾種方式,但終歸都是使用一種語法的:數組
#!/bin/bash array=(var1 var2 var3 var4 var5) echo ${array[@]:1}#從第一個元素取到最後一個 echo ${array[@]:1:3}#從第一個,取三個元素 echo ${array[@]::3}#從第0個開始,取三個 echo ${array[@]:-1:3}#從倒數第一個開始,取三個
這裏要注意的是:最後一個分號後面的數字,是要取的數量,而不是結束的索引值bash
這種說實話,用的不多,不過很方便的一種語法糖,請看:模塊化
#!/bin/bash array=(var1 vara2 varv3 vara4 varrr5) echo ${array[@]/v/V} #最小匹配,只替換每一個元素裏面第一個匹配到的字符 echo ${array[@]//v/V} #最大匹配,替換每一個元素裏面全部匹配到的字符 echo ${array[@]/v/} #刪除每一個元素第一個匹配到的字符 echo ${array[@]//v/} #刪除每一個元素所有匹配到的字符 echo ${array[@]/#v/V} #從左到右,只替換每一個元素中最左邊匹配到的字符 echo ${array[@]/%r/R} #從右到左,只替換每一個元素中最右邊匹配到的字符(測試以後很差使!) ehco ${array[@]#v*r} #最短匹配刪除每一個元素中的數據 ehco ${array[@]##v*r} #最長匹配刪除每一個元素中的數據 <<COMMENT 結果: Var1 Vara2 Varv3 Vara4 Varrr5 Var1 Vara2 VarV3 Vara4 Varrr5 ar1 ara2 arv3 ara4 arrr5 ar1 ara2 ar3 ara4 arrr5 Var1 Vara2 Varv3 Vara4 Varrr5 var1 vara2 varv3 vara4 varrr5 1 a2 v3 a4 rr5 1 a2 v3 a4 5 COMMENT
這東西相似於一個映射關係,咱們能夠用任意的文本做爲數組索引,而普通數組中的索引只能是0,1,2,3……另外關聯數組必需要進行聲明,不然使用的仍是普通數組:函數
declare -A array
下面是使用的代碼:
#!/bin/bash declare -A array array=([index1]=val1 [index2]=val2) echo ${array[index1]} echo ${array[index2]} array[index3]=varl3 # 獲取全部的值 echo ${array[@]} # 獲取全部的鍵 echo ${!array[@]} # 獲取長度 echo ${#array[@]}
注意後面 三個操做,對於普通數組來講,獲取全部鍵也能夠,可是結果是:0,1,2,3……
這個系列的第一篇文章中,介紹了三種算術運算方式:expr、$[]和bc。這裏再來一個很是經常使用的,針對整數的計算,這種方式不管從效率仍是開發效率上來講,都是最佳的,是最容易讓程序員接受學習的方式:(())
從上到下,,優先級遞減
直接上代碼:
#!/bin/bash # 這種是會報錯的,由於單純的兩個小括號並不是語法規範。要配合$進行取值使用 echo ((8*7)) # 這種沒問題,但沒有輸出。這只是單純的使用雙小括號進行了計算,不用取值操做 ((5+9)) # 這種也沒問題,仍是沒有輸出,由於也是隻是單純的計算了下,內部把結果值給了一個i變量 # 因爲自己也是沒有對雙小括號進行取值操做,因此也是不會語法出錯的 ((i=4+9)) # 這時候i爲13,由於上面賦了值了 echo $i # 這種就有語法錯誤了。由於要對雙小括號取值,而後給i進行賦值,但是取值操做要配合$使用 i=((4+91)) # 下面三種都是正確的使用雙小括號的方式 echo $((5+3)) echo $((i=5+3)) i=$((5+31)) # 雙小括號內部引用外部變量能夠不加$符號 i=$((i+9)) # 內部怎麼空格都不受語法的約束~放開了! i=$(( 9- 8)) # 注意優先級!內部是可使用邏輯運算的,爲真結果爲1,爲假結果爲0 echo $((i++**2&&3)) # 恩,沒錯,混合運算徹底沒問題(帶邏輯操做的混合運算) echo $((4+9*(2-3)&&4<7)) #這種會報錯,由於雙小括號不支持浮點數,只是整數的運算 echo $((4.4*7))
可見,雙小括號很是的方便與靈活,相較於$[],好用的多~之後經常使用~
shell沒有面向對象,用途的關係也不須要面向對象,函數就成了最後最後的模塊化的「堡壘」。咱們先來講書退出碼這個東西,在shell中相當重要。
我總喜歡這麼口語化的叫這東西是退出碼,其實全稱叫:退出狀態碼。他表達的是一個腳本(或是一個函數)最後的那條運行的命令的執行結果:正確爲0,報錯爲非0的值。上篇章中說到的各類if、while、until等,內部的判斷條件語句,就是根據這個來的。系統規定,這個碼,是一個數字,不能超過256,最大255。對於這個碼的設置與獲取,有下面三種:
注意,一旦執行命令(腳本、函數)結束後,應該使用$?立刻獲取,不然執行了其餘命令以後,退出碼就會變成其餘命令的了,$?只能獲取最後一條執行的結果。
#!/bin/bash ls # 這裏是0,由於上面的ls執行結果正確 echo $? ls ladjflaskjdf # 這裏執行結果爲2,由於上面的ladjflaskjdf並非目錄,執行報錯 echo $? exit 1 # 這裏不會執行了,由於上面的exit已經退出本次shell了,退出碼被設置成了1 echo "not exec" exit 0
定義很簡單,兩種方式:
# 第一種 function funal { commands } # 第二種 funal() { commands }
其實,函數,咱們就把他當成一個小腳本,使用方式,幾乎同樣
#!/bin/bash function func1 { echo "This is an example of a function" } count=1 while [ $count -le 5 ] do func1 count=$[ $count + 1 ] done echo "This is the end of the loop" func1 echo "Now this is the end of the script"
函數也能傳參,和咱們命令行中調用腳本如出一轍,函數內部使用參數也是一個樣子:
#!/bin/bash function funcl { # 注意:這裏獲取到的仍是本shell腳本的名字,並非函數名 echo "name is $0" echo $(($1+$2)) } func1 23 45
一樣的,咱們可使用數組進行傳參
#!/bin/bash function addarray { # 這是一種局部變量的聲明方式,外部獲取不到,也能夠和全局變量重名而不受影響 local sum=0 local newarray newarray=($(echo "$@")) for value in ${newarray[*]} do sum=$[ $sum + $value ] done echo $sum } myarray=(1 2 3 4 5) echo "The original array is: ${myarray[*]}" # 加echo的緣由是,將本來的數組進行輸出。單獨${myarray[*]}是不會輸出的,也就沒辦法賦值 arg1=$(echo ${myarray[*]}) result=$(addarray $arg1) echo "The result is $result"
shell中的函數,除了執行完以後退出以外,可使用兩種方式退出:
默認執行完以後,正常退出以後的狀態值是0。固然咱們可使用return語句,結束函數,並設置退出狀態值:
#!/bin/bash function funl { if [ $1 -eq 0 ] then echo "return 0" # 使用return提早退出函數 return 0 elif [$ -ne 0] then echo "return 1" return 1 fi } funl 0 echo $? funl 3 echo $? <<COMMENT 結果: return 0 0 return 1 1 COMMENT
和通常語言不一樣,shell尤其「精奇」!對於返回值這萬年函數的固有的"招數",居然不使用return關鍵字,這也是我使用、接觸、哪怕知道一點的全部計算機語言中,惟獨shell是這麼搞的!!!!!在shell中,函數的返回值,是函數內部全部的標準輸出,會使用空格分割,將全部的標準輸出組合成一個字符串,賦值給函數的結果引用變量,請看下面的:
#!/bin/bash function funl { # 下面三個命令都是有標準輸出的! ls -al echo 12 echo 34 } # 這裏把函數的標準輸出都保存到了一個變量中 var=$(funl) # 這種能夠把返回值變成一個數組 var_arr=($var) echo $var echo ${var_arr[0]} echo ${var_arr[1]} <<COMMENT 結果: 總用量 16 drwxrwxr-x 2 jicheng jicheng 4096 10月 19 15:20 . drwxrwxr-x 6 jicheng jicheng 4096 10月 16 10:35 .. -rw-rw-r-- 1 jicheng jicheng 58 10月 17 11:50 out -rwxrw-r-- 1 jicheng jicheng 183 10月 19 15:20 shell_test.sh 12 34 總用量 16 COMMENT
若是想在其餘當前shell腳本中使用其餘文件中定義的函數,要使用source命令,而且source命令還可使用.來代替的語法糖,請看下面:
#!/bin/bash # 在當前的shell腳本環境中,導入function_dict source ./function_dict # 這種是語法糖,通常使用這種,但要注意,點與後面的路徑有空格 . ./funtion_dict
涉及到函數使用,那範圍很是廣了,我這裏只寫一種,那就是使用函數進行遞歸操做!遞歸也是程序員常常涉及到的,稍微有點思緒的結構。咱們來使用shell,寫一個求階層的函數:
#!/bin/bash function factorial { if [ $1 -eq 1 ] then echo 1 else local temp=$(( $1 - 1 )) # 開始遞歸 local result=$(factorial $temp) echo $(( $result * $1 )) fi } read -p "Enter value:" value result=$(factorial $value) echo "result is:$result"
又一堆語法補充。我從網上也各處google了下,感受shell的本質的語法點仍是有不少的,例如尚未講的一大塊:正則表達式~(心累~哎)下面一章,緊接着我想寫一下實際的shell腳本實戰,根據現有的語法+上一些簡單的命令,來構建一些有用的。在那裏我再講正則吧~預期以下